#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;
}
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));
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;
}
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++;
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;
}
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));
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;
}
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++;
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;
}