|
|
@@ -1668,6 +1668,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
|
|
|
{
|
|
|
struct em28xx *dev = video_drvdata(file);
|
|
|
unsigned int n;
|
|
|
+ int j;
|
|
|
|
|
|
n = i->index;
|
|
|
if (n >= MAX_EM28XX_INPUT)
|
|
|
@@ -1687,6 +1688,12 @@ static int vidioc_enum_input(struct file *file, void *priv,
|
|
|
if (dev->is_webcam)
|
|
|
i->capabilities = 0;
|
|
|
|
|
|
+ /* Dynamically generates an audioset bitmask */
|
|
|
+ i->audioset = 0;
|
|
|
+ for (j = 0; j < MAX_EM28XX_INPUT; j++)
|
|
|
+ if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
|
|
|
+ i->audioset |= 1 << j;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -1712,11 +1719,24 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
+static int em28xx_fill_audio_input(struct em28xx *dev,
|
|
|
+ const char *s,
|
|
|
+ struct v4l2_audio *a,
|
|
|
+ unsigned int index)
|
|
|
{
|
|
|
- struct em28xx *dev = video_drvdata(file);
|
|
|
+ unsigned int idx = dev->amux_map[index];
|
|
|
|
|
|
- switch (a->index) {
|
|
|
+ /*
|
|
|
+ * With msp3400, almost all mappings use the default (amux = 0).
|
|
|
+ * The only one may use a different value is WinTV USB2, where it
|
|
|
+ * can also be SCART1 input.
|
|
|
+ * As it is very doubtful that we would see new boards with msp3400,
|
|
|
+ * let's just reuse the existing switch.
|
|
|
+ */
|
|
|
+ if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
|
|
|
+ idx = EM28XX_AMUX_LINE_IN;
|
|
|
+
|
|
|
+ switch (idx) {
|
|
|
case EM28XX_AMUX_VIDEO:
|
|
|
strcpy(a->name, "Television");
|
|
|
break;
|
|
|
@@ -1741,32 +1761,79 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
case EM28XX_AMUX_PCM_OUT:
|
|
|
strcpy(a->name, "PCM");
|
|
|
break;
|
|
|
+ case EM28XX_AMUX_UNUSED:
|
|
|
default:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
-
|
|
|
- a->index = dev->ctl_ainput;
|
|
|
+ a->index = index;
|
|
|
a->capability = V4L2_AUDCAP_STEREO;
|
|
|
|
|
|
+ em28xx_videodbg("%s: audio input index %d is '%s'\n",
|
|
|
+ s, a->index, a->name);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
|
|
|
+{
|
|
|
+ struct em28xx *dev = video_drvdata(file);
|
|
|
+
|
|
|
+ if (a->index >= MAX_EM28XX_INPUT)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ return em28xx_fill_audio_input(dev, __func__, a, a->index);
|
|
|
+}
|
|
|
+
|
|
|
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
+{
|
|
|
+ struct em28xx *dev = video_drvdata(file);
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
|
|
|
+ if (dev->ctl_ainput == dev->amux_map[i])
|
|
|
+ return em28xx_fill_audio_input(dev, __func__, a, i);
|
|
|
+
|
|
|
+ /* Should never happen! */
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
static int vidioc_s_audio(struct file *file, void *priv,
|
|
|
const struct v4l2_audio *a)
|
|
|
{
|
|
|
struct em28xx *dev = video_drvdata(file);
|
|
|
+ int idx, i;
|
|
|
|
|
|
if (a->index >= MAX_EM28XX_INPUT)
|
|
|
return -EINVAL;
|
|
|
- if (!INPUT(a->index)->type)
|
|
|
+
|
|
|
+ idx = dev->amux_map[a->index];
|
|
|
+
|
|
|
+ if (idx == EM28XX_AMUX_UNUSED)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ dev->ctl_ainput = idx;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * FIXME: This is wrong, as different inputs at em28xx_cards
|
|
|
+ * may have different audio outputs. So, the right thing
|
|
|
+ * to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
|
|
|
+ * With the current board definitions, this would work fine,
|
|
|
+ * as, currently, all boards fit.
|
|
|
+ */
|
|
|
+ for (i = 0; i < MAX_EM28XX_INPUT; i++)
|
|
|
+ if (idx == dev->amux_map[i])
|
|
|
+ break;
|
|
|
+ if (i == MAX_EM28XX_INPUT)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- dev->ctl_ainput = INPUT(a->index)->amux;
|
|
|
- dev->ctl_aoutput = INPUT(a->index)->aout;
|
|
|
+ dev->ctl_aoutput = INPUT(i)->aout;
|
|
|
|
|
|
if (!dev->ctl_aoutput)
|
|
|
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
|
|
|
|
|
|
+ em28xx_videodbg("%s: set audio input to %d\n", __func__,
|
|
|
+ dev->ctl_ainput);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -2304,6 +2371,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
|
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
|
|
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
|
|
.vidioc_enum_framesizes = vidioc_enum_framesizes,
|
|
|
+ .vidioc_enumaudio = vidioc_enumaudio,
|
|
|
.vidioc_g_audio = vidioc_g_audio,
|
|
|
.vidioc_s_audio = vidioc_s_audio,
|
|
|
|