V4L/DVB (3582): Implement correct msp3400 input/output routing
- implement VIDIOC_INT_S_AUDIO_ROUTING for msp3400 and tvaudio
- use the new command in bttv, pvrusb2 and em28xx.
- remove the now obsolete MSP_SET_MATRIX from msp3400 (yeah!)
- remove the obsolete VIDIOC_S_AUDIO from msp3400.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index be567ec..80e4a74 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -37,6 +37,7 @@
#include "bttvp.h"
#include <media/v4l2-common.h>
#include <media/tvaudio.h>
+#include <media/msp3400.h>
#include <linux/dma-mapping.h>
@@ -934,11 +935,9 @@
audio_mux(struct bttv *btv, int input, int mute)
{
int gpio_val, signal;
- struct v4l2_audio aud_input;
struct v4l2_control ctrl;
struct i2c_client *c;
- memset(&aud_input, 0, sizeof(aud_input));
gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
bttv_tvcards[btv->c.type].gpiomask);
signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
@@ -953,7 +952,6 @@
gpio_val = bttv_tvcards[btv->c.type].gpiomute;
else
gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
- aud_input.index = btv->audio;
gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
if (bttv_gpio)
@@ -962,15 +960,51 @@
return 0;
ctrl.id = V4L2_CID_AUDIO_MUTE;
- /* take automute into account, just btv->mute is not enough */
- ctrl.value = mute;
+ ctrl.value = btv->mute;
bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
c = btv->i2c_msp34xx_client;
- if (c)
- c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
+ if (c) {
+ struct v4l2_routing route;
+
+ /* Note: the inputs tuner/radio/extern/intern are translated
+ to msp routings. This assumes common behavior for all msp3400
+ based TV cards. When this assumption fails, then the
+ specific MSP routing must be added to the card table.
+ For now this is sufficient. */
+ switch (input) {
+ case TVAUDIO_INPUT_RADIO:
+ route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
+ MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+ break;
+ case TVAUDIO_INPUT_EXTERN:
+ route.input = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
+ MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+ break;
+ case TVAUDIO_INPUT_INTERN:
+ /* Yes, this is the same input as for RADIO. I doubt
+ if this is ever used. The only board with an INTERN
+ input is the BTTV_BOARD_AVERMEDIA98. I wonder how
+ that was tested. My guess is that the whole INTERN
+ input does not work. */
+ route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
+ MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+ break;
+ case TVAUDIO_INPUT_TUNER:
+ default:
+ route.input = MSP_INPUT_DEFAULT;
+ break;
+ }
+ route.output = MSP_OUTPUT_DEFAULT;
+ c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
c = btv->i2c_tvaudio_client;
- if (c)
- c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
+ if (c) {
+ struct v4l2_routing route;
+
+ route.input = input;
+ route.output = 0;
+ c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ }
return 0;
}
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 2d68a27..f62fd706b 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -28,8 +28,9 @@
#include <linux/i2c.h>
#include <linux/usb.h>
#include <media/tuner.h>
-#include <media/audiochip.h>
+#include <media/msp3400.h>
#include <media/tveeprom.h>
+#include <media/audiochip.h>
#include <media/v4l2-common.h>
#include "em28xx.h"
@@ -146,11 +147,12 @@
.input = {{
.type = EM28XX_VMUX_TELEVISION,
.vmux = 0,
- .amux = 6,
+ .amux = MSP_INPUT_DEFAULT,
},{
.type = EM28XX_VMUX_SVIDEO,
.vmux = 2,
- .amux = 1,
+ .amux = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
+ MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART),
}},
},
[EM2820_BOARD_MSI_VOX_USB_2] = {
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 780342f..dfba33d 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -38,6 +38,7 @@
#include "em28xx.h"
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include <media/msp3400.h>
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
@@ -216,9 +217,14 @@
em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
if (dev->has_msp34xx) {
+ struct v4l2_routing route;
+
if (dev->i2s_speed)
em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
- em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput);
+ route.input = dev->ctl_ainput;
+ route.output = MSP_OUTPUT(MSP_OUT_SCART1_DA);
+ /* Note: this is msp3400 specific */
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
ainput = EM28XX_AUDIO_SRC_TUNER;
em28xx_audio_source(dev, ainput);
} else {
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 0425028..8ba1c96 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -555,7 +555,6 @@
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct msp_state *state = i2c_get_clientdata(client);
- int scart = -1;
if (msp_debug >= 2)
v4l_i2c_print_ioctl(client, cmd);
@@ -660,15 +659,6 @@
break;
}
- /* msp34xx specific */
- case MSP_SET_MATRIX:
- {
- struct msp_matrix *mspm = arg;
-
- msp_set_scart(client, mspm->input - 1, mspm->output);
- break;
- }
-
/* --- v4l2 ioctls --- */
case VIDIOC_S_STD:
{
@@ -682,36 +672,38 @@
return 0;
}
- case VIDIOC_S_AUDIO:
+ case VIDIOC_INT_G_AUDIO_ROUTING:
{
- struct v4l2_audio *sarg = arg;
+ struct v4l2_routing *rt = arg;
- switch (sarg->index) {
- case TVAUDIO_INPUT_RADIO:
- /* Hauppauge uses IN2 for the radio */
- state->mode = MSP_MODE_FM_RADIO;
- scart = SCART_IN2;
- break;
- case TVAUDIO_INPUT_EXTERN:
- /* IN1 is often used for external input ... */
- state->mode = MSP_MODE_EXTERN;
- scart = SCART_IN1;
- break;
- case TVAUDIO_INPUT_INTERN:
- /* ... sometimes it is IN2 through ;) */
- state->mode = MSP_MODE_EXTERN;
- scart = SCART_IN2;
- break;
- case TVAUDIO_INPUT_TUNER:
- state->mode = -1;
- break;
+ *rt = state->routing;
+ break;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ {
+ struct v4l2_routing *rt = arg;
+ int tuner = (rt->input >> 3) & 1;
+ int old_tuner = (state->routing.input >> 3) & 1;
+ int sc_in = rt->input & 0x7;
+ int sc1_out = rt->output & 0xf;
+ int sc2_out = (rt->output >> 4) & 0xf;
+ u16 val;
+
+ state->routing = *rt;
+ if (state->opmode == OPMODE_AUTOSELECT) {
+ val = msp_read_dem(client, 0x30) & ~0x100;
+ msp_write_dem(client, 0x30, val | (tuner ? 0x100 : 0));
+ } else {
+ val = msp_read_dem(client, 0xbb) & ~0x100;
+ msp_write_dem(client, 0xbb, val | (tuner ? 0x100 : 0));
}
- if (scart >= 0) {
- state->rxsubchans = V4L2_TUNER_SUB_STEREO;
- msp_set_scart(client, scart, 0);
- }
+ msp_set_scart(client, sc_in, 0);
+ msp_set_scart(client, sc1_out, 1);
+ msp_set_scart(client, sc2_out, 2);
msp_set_audmode(client);
- msp_wake_thread(client);
+ if (tuner != old_tuner)
+ msp_wake_thread(client);
break;
}
@@ -941,6 +933,9 @@
state->muted = 0;
state->i2s_mode = 0;
init_waitqueue_head(&state->wq);
+ /* These are the reset input/output positions */
+ state->routing.input = MSP_INPUT_DEFAULT;
+ state->routing.output = MSP_OUTPUT_DEFAULT;
state->rev1 = msp_read_dsp(client, 0x1e);
if (state->rev1 != -1)
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index 04821eb..1940748 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -4,6 +4,8 @@
#ifndef MSP3400_DRIVER_H
#define MSP3400_DRIVER_H
+#include <media/msp3400.h>
+
/* ---------------------------------------------------------------------- */
/* This macro is allowed for *constants* only, gcc must calculate it
@@ -72,7 +74,7 @@
int i2s_mode;
int main, second; /* sound carrier */
int input;
- int source; /* see msp34xxg_set_source */
+ struct v4l2_routing routing;
/* v4l2 */
int audmode;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 9ee8dc2..1c794c3 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -187,13 +187,14 @@
{
struct msp_state *state = i2c_get_clientdata(client);
struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode];
+ int tuner = (state->routing.input >> 3) & 1;
int i;
v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode);
state->mode = mode;
state->rxsubchans = V4L2_TUNER_SUB_MONO;
- msp_write_dem(client, 0x00bb, data->ad_cv);
+ msp_write_dem(client, 0x00bb, data->ad_cv | (tuner ? 0x100 : 0));
for (i = 5; i >= 0; i--) /* fir 1 */
msp_write_dem(client, 0x0001, data->fir1[i]);
@@ -783,34 +784,6 @@
* struct msp: only norm, acb and source are really used in this mode
*/
-/* set the same 'source' for the loudspeaker, scart and quasi-peak detector
- * the value for source is the same as bit 15:8 of DSP registers 0x08,
- * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B
- */
-static void msp34xxg_set_source(struct i2c_client *client, int source)
-{
- struct msp_state *state = i2c_get_clientdata(client);
-
- /* fix matrix mode to stereo and let the msp choose what
- * to output according to 'source', as recommended
- * for MONO (source==0) downmixing set bit[7:0] to 0x30
- */
- int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20);
-
- v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value);
- msp_set_source(client, value);
- /*
- * set identification threshold. Personally, I
- * I set it to a higher value that the default
- * of 0x190 to ignore noisy stereo signals.
- * this needs tuning. (recommended range 0x00a0-0x03c0)
- * 0x7f0 = forced mono mode
- */
- /* a2 threshold for stereo/bilingual */
- msp_write_dem(client, 0x22, msp_stereo_thresh);
- state->source = source;
-}
-
static int msp34xxg_modus(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
@@ -843,10 +816,65 @@
return 0x0001;
}
+static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
+ {
+ struct msp_state *state = i2c_get_clientdata(client);
+ int source, matrix;
+
+ switch (state->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ source = 0; /* mono only */
+ matrix = 0x30;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ source = 3; /* stereo or A */
+ matrix = 0x00;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ source = 4; /* stereo or B */
+ matrix = 0x10;
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ default:
+ source = 1; /* stereo or A|B */
+ matrix = 0x20;
+ break;
+ }
+
+ if (in == MSP_DSP_OUT_TUNER)
+ source = (source << 8) | 0x20;
+ /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
+ instead of 11, 12, 13. So we add one for that msp version. */
+ else if (in >= MSP_DSP_OUT_MAIN_AVC && state->has_dolby_pro_logic)
+ source = ((in + 1) << 8) | matrix;
+ else
+ source = (in << 8) | matrix;
+
+ v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n",
+ in, source, reg);
+ msp_write_dsp(client, reg, source);
+}
+
+static void msp34xxg_set_sources(struct i2c_client *client)
+{
+ struct msp_state *state = i2c_get_clientdata(client);
+ u32 in = state->routing.input;
+
+ msp34xxg_set_source(client, 0x0008, (in >> 4) & 0xf);
+ /* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
+ msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf);
+ msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf);
+ msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf);
+ if (state->has_scart23_in_scart2_out)
+ msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf);
+ msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf);
+}
+
/* (re-)initialize the msp34xxg */
static void msp34xxg_reset(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
+ int tuner = (state->routing.input >> 3) & 1;
int modus;
/* initialize std to 1 (autodetect) to signal that no standard is
@@ -864,11 +892,12 @@
/* step-by-step initialisation, as described in the manual */
modus = msp34xxg_modus(client);
+ modus |= tuner ? 0x100 : 0;
msp_write_dem(client, 0x30, modus);
/* write the dsps that may have an influence on
standard/audio autodetection right now */
- msp34xxg_set_source(client, state->source);
+ msp34xxg_set_sources(client);
msp_write_dsp(client, 0x0d, 0x1900); /* scart */
msp_write_dsp(client, 0x0e, 0x3000); /* FM */
@@ -896,7 +925,6 @@
v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
- state->source = 1; /* default */
for (;;) {
v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
msp_sleep(state, -1);
@@ -993,7 +1021,6 @@
static void msp34xxg_set_audmode(struct i2c_client *client)
{
struct msp_state *state = i2c_get_clientdata(client);
- int source;
if (state->std == 0x20) {
if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) &&
@@ -1005,25 +1032,7 @@
}
}
- switch (state->audmode) {
- case V4L2_TUNER_MODE_MONO:
- source = 0; /* mono only */
- break;
- case V4L2_TUNER_MODE_STEREO:
- source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */
- /* problem: that could also mean 2 (scart input) */
- break;
- case V4L2_TUNER_MODE_LANG1:
- source = 3; /* stereo or A */
- break;
- case V4L2_TUNER_MODE_LANG2:
- source = 4; /* stereo or B */
- break;
- default:
- source = 1;
- break;
- }
- msp34xxg_set_source(client, source);
+ msp34xxg_set_sources(client);
}
void msp_set_audmode(struct i2c_client *client)
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 15fd55f..4e6d030 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1682,6 +1682,30 @@
case VIDIOC_S_CTRL:
return tvaudio_set_ctrl(chip, arg);
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ {
+ struct v4l2_routing *rt = arg;
+
+ rt->input = chip->input;
+ rt->output = 0;
+ break;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ {
+ struct v4l2_routing *rt = arg;
+
+ if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
+ return -EINVAL;
+ /* There are four inputs: tuner, radio, extern and intern. */
+ chip->input = rt->input;
+ if (chip->muted)
+ break;
+ chip_write_masked(chip, desc->inputreg,
+ desc->inputmap[chip->input], desc->inputmask);
+ break;
+ }
+
case VIDIOC_S_AUDIO:
{
struct v4l2_audio *sarg = arg;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index d1234d7..6824ee04 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -312,7 +312,6 @@
[_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP",
#endif
[_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO",
- [_IOC_NR(MSP_SET_MATRIX)] = "MSP_SET_MATRIX",
[_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR",
[_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY",
@@ -431,12 +430,6 @@
printk ("%s: value=%d\n", s, *p);
break;
}
- case MSP_SET_MATRIX:
- {
- struct msp_matrix *p=arg;
- printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
- break;
- }
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_ENUMAUDIO:
@@ -465,7 +458,7 @@
struct v4l2_buffer *p=arg;
struct v4l2_timecode *tc=&p->timecode;
printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, "
- "bytesused=%d, flags=0x%08d, "
+ "bytesused=%d, flags=0x%08x, "
"field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
s,
(p->timestamp.tv_sec/3600),
@@ -479,7 +472,7 @@
prt_names(p->memory,v4l2_memory_names),
p->m.userptr);
printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08d, frames=%d, userbits=0x%p",
+ "flags=0x%08x, frames=%d, userbits=0x%08p\n",
s,tc->hours,tc->minutes,tc->seconds,
tc->type, tc->flags, tc->frames, tc->userbits);
break;
@@ -665,7 +658,7 @@
case VIDIOC_INT_G_VIDEO_ROUTING:
{
struct v4l2_routing *p=arg;
- printk ("%s: input=%d, output=%d\n", s, p->input, p->output);
+ printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
break;
}
case VIDIOC_G_SLICED_VBI_CAP:
diff --git a/include/media/msp3400.h b/include/media/msp3400.h
index 26e2658..0be61a0 100644
--- a/include/media/msp3400.h
+++ b/include/media/msp3400.h
@@ -145,9 +145,14 @@
MSP_DSP_TO_SCART1(sc_i2s_src) | \
MSP_DSP_TO_SCART2(sc_i2s_src) | \
MSP_DSP_TO_I2S(sc_i2s_src))
+#define MSP_INPUT_DEFAULT MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1, \
+ MSP_DSP_OUT_TUNER, MSP_DSP_OUT_TUNER)
#define MSP_OUTPUT(sc) \
(MSP_OUT_TO_SCART1(sc) | \
MSP_OUT_TO_SCART2(sc))
+/* This equals the RESET position of the msp3400 ACB register */
+#define MSP_OUTPUT_DEFAULT (MSP_OUT_TO_SCART1(MSP_OUT_SCART3) | \
+ MSP_OUT_TO_SCART2(MSP_OUT_SCART1_DA))
/* Tuner inputs vs. msp version */
/* Chip TUNER_1 TUNER_2
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 0713047..642520a 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -123,14 +123,6 @@
/* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */
#define AUDC_SET_RADIO _IO('d',88)
-/* msp3400 ioctl: will be removed in the near future, to be replaced by
- VIDIOC_INT_S_AUDIO_ROUTING. */
-struct msp_matrix {
- int input;
- int output;
-};
-#define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix)
-
/* tuner ioctls */
/* Sets tuner type and its I2C addr */