v4l2-compliance: add tuner/modulator tests.
authorHans Verkuil <hverkuil@xs4all.nl>
Sat, 8 Jan 2011 18:39:46 +0000 (19:39 +0100)
committerHans Verkuil <hverkuil@xs4all.nl>
Sat, 8 Jan 2011 18:39:46 +0000 (19:39 +0100)
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
utils/v4l2-compliance/v4l2-compliance.cpp
utils/v4l2-compliance/v4l2-compliance.h
utils/v4l2-compliance/v4l2-test-input-output.cpp

index 1e3661e..eee697f 100644 (file)
@@ -283,8 +283,8 @@ int main(int argc, char **argv)
        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 radio_node = { -1, true };
+       struct node radio_node2 = { -1, true };
        struct node vbi_node = { -1 };
        struct node vbi_node2 = { -1 };
 
@@ -486,12 +486,14 @@ int main(int argc, char **argv)
 
        printf("Input ioctls:\n");
        if (test[TestInput]) {
+               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("\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)));
        }
index cbd7e7b..9a17c1b 100644 (file)
@@ -29,6 +29,7 @@ extern unsigned caps;
 
 struct node {
        int fd;
+       bool is_radio;
        unsigned caps;
        unsigned tuners;
        unsigned modulators;
@@ -58,10 +59,12 @@ int testRegister(struct node *node);
 int testLogStatus(struct node *node);
 
 // Input ioctl tests
+int testTuner(struct node *node);
 int testInput(struct node *node);
 int testInputAudio(struct node *node);
 
 // Output ioctl tests
+int testModulator(struct node *node);
 int testOutput(struct node *node);
 int testOutputAudio(struct node *node);
 
index 6f9fabe..1cdd435 100644 (file)
 
 #define MAGIC 0x1eadbeef
 
-static int validInput(const struct v4l2_input *descr, unsigned i, unsigned max_audio)
+static int validTuner(struct node *node, const struct v4l2_tuner &tuner,
+               unsigned t, v4l2_std_id std)
 {
-       __u32 mask = (1 << max_audio) - 1;
+       bool valid_modes[5] = { true, false, false, true, false };
+       bool tv = !node->is_radio;
+       enum v4l2_tuner_type type = tv ? V4L2_TUNER_ANALOG_TV : V4L2_TUNER_RADIO;
+       __u32 audmode;
 
-       if (descr->index != i)
+       if (tuner.index != t)
                return fail("invalid index\n");
-       if (check_ustring(descr->name, sizeof(descr->name)))
+       if (check_ustring(tuner.name, sizeof(tuner.name)))
                return fail("invalid name\n");
-       if (descr->type != V4L2_INPUT_TYPE_TUNER && descr->type != V4L2_INPUT_TYPE_CAMERA)
+       if (check_0(tuner.reserved, sizeof(tuner.reserved)))
+               return fail("non-zero reserved fields\n");
+       if (tuner.type != type)
+               return fail("invalid tuner type %d\n", tuner.type);
+       if (tv && (tuner.capability & V4L2_TUNER_CAP_RDS))
+               return fail("RDS for TV tuner?\n");
+       if (!tv && (tuner.capability & (V4L2_TUNER_CAP_NORM |
+                                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2)))
+               return fail("TV capabilities for radio tuner?\n");
+       if (tuner.rangelow >= tuner.rangehigh)
+               return fail("rangelow >= rangehigh\n");
+       if (tuner.rangelow == 0 || tuner.rangehigh == 0xffffffff)
+               return fail("invalid rangelow or rangehigh\n");
+       if (!(tuner.capability & V4L2_TUNER_CAP_STEREO) &&
+                       (tuner.rxsubchans & V4L2_TUNER_SUB_STEREO))
+               return fail("stereo subchan, but no stereo caps?\n");
+       if (!(tuner.capability & V4L2_TUNER_CAP_LANG1) &&
+                       (tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
+               return fail("lang1 subchan, but no lang1 caps?\n");
+       if (!(tuner.capability & V4L2_TUNER_CAP_LANG2) &&
+                       (tuner.rxsubchans & V4L2_TUNER_SUB_LANG2))
+               return fail("lang2 subchan, but no lang2 caps?\n");
+       if (!(tuner.capability & V4L2_TUNER_CAP_RDS) &&
+                       (tuner.rxsubchans & V4L2_TUNER_SUB_RDS))
+               return fail("RDS subchan, but no RDS caps?\n");
+       if (std == V4L2_STD_NTSC_M && (tuner.rxsubchans & V4L2_TUNER_SUB_LANG1))
+               return fail("LANG1 subchan, but NTSC-M standard\n");
+       if (tuner.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
+               return fail("invalid audio mode\n");
+       // Ambiguous whether this is allowed or not
+       //              if (!tv && tuner.audmode > V4L2_TUNER_MODE_STEREO)
+       //                      return -16;
+       if (tuner.signal > 65535)
+               return fail("signal too large\n");
+       if (tuner.capability & V4L2_TUNER_CAP_STEREO)
+               valid_modes[V4L2_TUNER_MODE_STEREO] = true;
+       if (tuner.capability & V4L2_TUNER_CAP_LANG2) {
+               valid_modes[V4L2_TUNER_MODE_LANG2] = true;
+               valid_modes[V4L2_TUNER_MODE_LANG1_LANG2] = true;
+       }
+       for (audmode = 0; audmode < 5; audmode++) {
+               struct v4l2_tuner tun = { 0 };
+
+               tun.index = tuner.index;
+               tun.audmode = audmode;
+               if (doioctl(node, VIDIOC_S_TUNER, &tun))
+                       return fail("cannot set audmode %d\n", audmode);
+               if (doioctl(node, VIDIOC_G_TUNER, &tun))
+                       fail("failure to get new tuner audmode\n");
+               if (tun.audmode > V4L2_TUNER_MODE_LANG1_LANG2)
+                       return fail("invalid new audmode\n");
+               // Ambiguous whether this is allowed or not
+               //      if (!tv && tun.audmode > V4L2_TUNER_MODE_STEREO)
+               //              return -21;
+               //      if (!valid_modes[tun.audmode])
+               //              return fail("accepted invalid audmode %d\n", audmode);
+       }
+       return 0;
+}
+
+int testTuner(struct node *node)
+{
+       struct v4l2_tuner tuner;
+       v4l2_std_id std;
+       unsigned t = 0;
+       int ret;
+
+       if (doioctl(node, VIDIOC_G_STD, &std))
+               std = 0;
+
+       for (;;) {
+               memset(&tuner, 0xff, sizeof(tuner));
+               memset(tuner.reserved, 0, sizeof(tuner.reserved));
+               tuner.index = t;
+               ret = doioctl(node, VIDIOC_G_TUNER, &tuner);
+               if (ret == EINVAL && t == 0)
+                       return -ENOSYS;
+               if (ret == EINVAL)
+                       break;
+               if (ret)
+                       return fail("couldn't get tuner %d\n", t);
+               if (validTuner(node, tuner, t, std))
+                       return fail("invalid tuner %d\n", t);
+               t++;
+               node->tuners++;
+       }
+       memset(&tuner, 0, sizeof(tuner));
+       tuner.index = t;
+       if (doioctl(node, VIDIOC_S_TUNER, &tuner) != EINVAL)
+               return fail("could set invalid tuner %d\n", t);
+       return 0;
+}
+
+static int validInput(struct node *node, const struct v4l2_input &descr, unsigned i)
+{
+       __u32 mask = (1 << node->audio_inputs) - 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)
+       if (descr.type == V4L2_INPUT_TYPE_CAMERA && descr.tuner)
                return fail("invalid tuner\n");
-       if (!(descr->capabilities & V4L2_IN_CAP_STD) && descr->std)
+       if (!(descr.capabilities & V4L2_IN_CAP_STD) && descr.std)
                return fail("invalid std\n");
-       if ((descr->capabilities & V4L2_IN_CAP_STD) && !descr->std)
+       if ((descr.capabilities & V4L2_IN_CAP_STD) && !descr.std)
                return fail("std == 0\n");
-       if (descr->capabilities & ~0x7)
+       if (descr.capabilities & ~0x7)
                return fail("invalid capabilities\n");
-       if (check_0(descr->reserved, sizeof(descr->reserved)))
+       if (check_0(descr.reserved, sizeof(descr.reserved)))
                return fail("non-zero reserved fields\n");
-       if (descr->status & ~0x07070337)
+       if (descr.status & ~0x07070337)
                return fail("invalid status\n");
-       if (descr->status & 0x02070000)
+       if (descr.status & 0x02070000)
                return fail("use of deprecated digital video status\n");
-       if (descr->audioset & ~mask)
+       if (descr.audioset & ~mask)
                return fail("invalid audioset\n");
+       if (descr.tuner && descr.tuner >= node->tuners)
+               return fail("invalid tuner\n");
        return 0;
 }
 
@@ -91,7 +198,7 @@ int testInput(struct node *node)
                        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))
+               if (validInput(node, descr, i))
                        return fail("invalid attributes for input %d\n", i);
                for (a = 0; a <= node->audio_inputs; a++) {
                        memset(&audio, 0, sizeof(audio));
@@ -112,19 +219,19 @@ int testInput(struct node *node)
        return 0;
 }
 
-static int validInputAudio(const struct v4l2_audio *descr, unsigned i)
+static int validInputAudio(const struct v4l2_audio &descr, unsigned i)
 {
-       if (descr->index != i)
+       if (descr.index != i)
                return fail("invalid index\n");
-       if (check_ustring(descr->name, sizeof(descr->name)))
+       if (check_ustring(descr.name, sizeof(descr.name)))
                return fail("invalid name\n");
-       if (descr->capability & ~0x3)
+       if (descr.capability & ~0x3)
                return fail("invalid capabilities\n");
-       if (descr->mode != 0 && descr->mode != V4L2_AUDMODE_AVL)
+       if (descr.mode != 0 && descr.mode != V4L2_AUDMODE_AVL)
                return fail("invalid mode\n");
-       if (!(descr->capability & V4L2_AUDCAP_AVL) && descr->mode)
+       if (!(descr.capability & V4L2_AUDCAP_AVL) && descr.mode)
                return fail("mode != 0\n");
-       if (check_0(descr->reserved, sizeof(descr->reserved)))
+       if (check_0(descr.reserved, sizeof(descr.reserved)))
                return fail("non-zero reserved fields\n");
        return 0;
 }
@@ -146,7 +253,7 @@ int testInputAudio(struct node *node)
                        break;
                if (ret)
                        return fail("could not enumerate audio input %d\n", i);
-               if (validInputAudio(&input, i))
+               if (validInputAudio(input, i))
                        return fail("invalid attributes for audio input %d\n", i);
                node->audio_inputs++;
                i++;
@@ -168,33 +275,100 @@ int testInputAudio(struct node *node)
                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))
+       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)
+static int validModulator(struct node *node, const struct v4l2_modulator &mod, unsigned m)
 {
-       __u32 mask = (1 << max_audio) - 1;
+       bool tv = !node->is_radio;
 
-       if (descr->index != o)
+       if (mod.index != m)
                return fail("invalid index\n");
-       if (check_ustring(descr->name, sizeof(descr->name)))
+       if (check_ustring(mod.name, sizeof(mod.name)))
                return fail("invalid name\n");
-       if (descr->type != V4L2_OUTPUT_TYPE_MODULATOR && descr->type != V4L2_OUTPUT_TYPE_ANALOG)
+       if (check_0(mod.reserved, sizeof(mod.reserved)))
+               return fail("non-zero reserved fields\n");
+       if (tv && (mod.capability & V4L2_TUNER_CAP_RDS))
+               return fail("RDS for TV modulator?\n");
+       if (!tv && (mod.capability & (V4L2_TUNER_CAP_NORM |
+                                       V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2)))
+               return fail("TV capabilities for radio modulator?\n");
+       if (mod.rangelow >= mod.rangehigh)
+               return fail("rangelow >= rangehigh\n");
+       if (mod.rangelow == 0 || mod.rangehigh == 0xffffffff)
+               return fail("invalid rangelow or rangehigh\n");
+       if (!(mod.capability & V4L2_TUNER_CAP_STEREO) &&
+                       (mod.txsubchans & V4L2_TUNER_SUB_STEREO))
+               return fail("stereo subchan, but no stereo caps?\n");
+       if (!(mod.capability & V4L2_TUNER_CAP_LANG1) &&
+                       (mod.txsubchans & V4L2_TUNER_SUB_LANG1))
+               return fail("lang1 subchan, but no lang1 caps?\n");
+       if (!(mod.capability & V4L2_TUNER_CAP_LANG2) &&
+                       (mod.txsubchans & V4L2_TUNER_SUB_LANG2))
+               return fail("lang2 subchan, but no lang2 caps?\n");
+       if (!(mod.capability & V4L2_TUNER_CAP_RDS) &&
+                       (mod.txsubchans & V4L2_TUNER_SUB_RDS))
+               return fail("RDS subchan, but no RDS caps?\n");
+       return 0;
+}
+
+int testModulator(struct node *node)
+{
+       struct v4l2_modulator mod;
+       unsigned m = 0;
+       int ret;
+
+       for (;;) {
+               memset(&mod, 0xff, sizeof(mod));
+               memset(mod.reserved, 0, sizeof(mod.reserved));
+               mod.index = m;
+               ret = doioctl(node, VIDIOC_G_MODULATOR, &mod);
+               if (ret == EINVAL && m == 0)
+                       return -ENOSYS;
+               if (ret == EINVAL)
+                       break;
+               if (ret)
+                       return fail("couldn't get modulator %d\n", m);
+               if (validModulator(node, mod, m))
+                       return fail("invalid modulator %d\n", m);
+               if (doioctl(node, VIDIOC_S_MODULATOR, &mod))
+                       return fail("cannot set modulator %d\n", m);
+               m++;
+               node->modulators++;
+       }
+       memset(&mod, 0, sizeof(mod));
+       mod.index = m;
+       if (doioctl(node, VIDIOC_S_MODULATOR, &mod) != EINVAL)
+               return fail("could set invalid modulator %d\n", m);
+       return 0;
+}
+
+static int validOutput(struct node *node, const struct v4l2_output &descr, unsigned o)
+{
+       __u32 mask = (1 << node->audio_outputs) - 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)
+       if (descr.type == V4L2_OUTPUT_TYPE_ANALOG && descr.modulator)
                return fail("invalid modulator\n");
-       if (!(descr->capabilities & V4L2_OUT_CAP_STD) && descr->std)
+       if (!(descr.capabilities & V4L2_OUT_CAP_STD) && descr.std)
                return fail("invalid std\n");
-       if ((descr->capabilities & V4L2_OUT_CAP_STD) && !descr->std)
+       if ((descr.capabilities & V4L2_OUT_CAP_STD) && !descr.std)
                return fail("std == 0\n");
-       if (descr->capabilities & ~0x7)
+       if (descr.capabilities & ~0x7)
                return fail("invalid capabilities\n");
-       if (check_0(descr->reserved, sizeof(descr->reserved)))
+       if (check_0(descr.reserved, sizeof(descr.reserved)))
                return fail("non-zero reserved fields\n");
-       if (descr->audioset & ~mask)
+       if (descr.audioset & ~mask)
                return fail("invalid audioset\n");
+       if (descr.modulator && descr.modulator >= node->modulators)
+               return fail("invalid modulator\n");
        return 0;
 }
 
@@ -225,7 +399,7 @@ int testOutput(struct node *node)
                        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))
+               if (validOutput(node, descr, o))
                        return fail("invalid attributes for output %d\n", o);
                for (a = 0; a <= node->audio_outputs; a++) {
                        memset(&audio, 0, sizeof(audio));
@@ -246,17 +420,17 @@ int testOutput(struct node *node)
        return 0;
 }
 
-static int validOutputAudio(const struct v4l2_audioout *descr, unsigned o)
+static int validOutputAudio(const struct v4l2_audioout &descr, unsigned o)
 {
-       if (descr->index != o)
+       if (descr.index != o)
                return fail("invalid index\n");
-       if (check_ustring(descr->name, sizeof(descr->name)))
+       if (check_ustring(descr.name, sizeof(descr.name)))
                return fail("invalid name\n");
-       if (descr->capability)
+       if (descr.capability)
                return fail("invalid capabilities\n");
-       if (descr->mode)
+       if (descr.mode)
                return fail("invalid mode\n");
-       if (check_0(descr->reserved, sizeof(descr->reserved)))
+       if (check_0(descr.reserved, sizeof(descr.reserved)))
                return fail("non-zero reserved fields\n");
        return 0;
 }
@@ -278,7 +452,7 @@ int testOutputAudio(struct node *node)
                        break;
                if (ret)
                        return fail("could not enumerate audio output %d\n", o);
-               if (validOutputAudio(&output, o))
+               if (validOutputAudio(output, o))
                        return fail("invalid attributes for audio output %d\n", o);
                node->audio_outputs++;
                o++;
@@ -300,7 +474,7 @@ int testOutputAudio(struct node *node)
                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))
+       if (validOutputAudio(output, output.index))
                return fail("invalid attributes for audio output %d\n", output.index);
        return 0;
 }