diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 190 | ||||
-rw-r--r-- | drivers/media/video/msp3400-kthreads.c | 40 | ||||
-rw-r--r-- | drivers/media/video/msp3400.h | 6 |
3 files changed, 156 insertions, 80 deletions
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 0c2ab7e9d1c..04a05d7dd47 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -283,33 +283,57 @@ void msp_set_scart(struct i2c_client *client, int in, int out) void msp_set_mute(struct i2c_client *client) { + struct msp_state *state = i2c_get_clientdata(client); + v4l_dbg(1, client, "mute audio\n"); - msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ - msp_write_dsp(client, 0x0006, 0); /* headphones */ + msp_write_dsp(client, 0x0000, 0); + msp_write_dsp(client, 0x0007, 1); + if (state->has_scart2_out_volume) + msp_write_dsp(client, 0x0040, 1); + if (state->has_headphones) + msp_write_dsp(client, 0x0006, 0); } void msp_set_audio(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int val = 0, bal = 0, bass, treble; + int bal = 0, bass, treble, loudness; + int val = 0; if (!state->muted) val = (state->volume * 0x7f / 65535) << 8; + + v4l_dbg(1, client, "mute=%s volume=%d\n", + state->muted ? "on" : "off", state->volume); + + msp_write_dsp(client, 0x0000, val); + msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); + if (state->has_scart2_out_volume) + msp_write_dsp(client, 0x0040, state->muted ? 0x1 : (val | 0x1)); + if (state->has_headphones) + msp_write_dsp(client, 0x0006, val); + if (!state->has_sound_processing) + return; + if (val) - bal = (state->balance / 256) - 128; + bal = (u8)((state->balance / 256) - 128); bass = ((state->bass - 32768) * 0x60 / 65535) << 8; treble = ((state->treble - 32768) * 0x60 / 65535) << 8; + loudness = state->loudness ? ((5 * 4) << 8) : 0; - v4l_dbg(1, client, "mute=%s volume=%d balance=%d bass=%d treble=%d\n", - state->muted ? "on" : "off", state->volume, state->balance, - state->bass, state->treble); + v4l_dbg(1, client, "balance=%d bass=%d treble=%d loudness=%d\n", + state->balance, state->bass, state->treble, state->loudness); - msp_write_dsp(client, 0x0000, val); /* loudspeaker */ - msp_write_dsp(client, 0x0006, val); /* headphones */ - msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); msp_write_dsp(client, 0x0001, bal << 8); - msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ - msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ + msp_write_dsp(client, 0x0002, bass); + msp_write_dsp(client, 0x0003, treble); + msp_write_dsp(client, 0x0004, loudness); + if (!state->has_headphones) + return; + msp_write_dsp(client, 0x0030, bal << 8); + msp_write_dsp(client, 0x0031, bass); + msp_write_dsp(client, 0x0032, treble); + msp_write_dsp(client, 0x0033, loudness); } int msp_modus(struct i2c_client *client) @@ -421,7 +445,7 @@ static void msp_any_detect_stereo(struct i2c_client *client) } } -static struct v4l2_queryctrl msp_qctrl[] = { +static struct v4l2_queryctrl msp_qctrl_std[] = { { .id = V4L2_CID_AUDIO_VOLUME, .name = "Volume", @@ -432,15 +456,6 @@ static struct v4l2_queryctrl msp_qctrl[] = { .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, },{ - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .flags = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, @@ -449,6 +464,19 @@ static struct v4l2_queryctrl msp_qctrl[] = { .default_value = 1, .flags = 0, .type = V4L2_CTRL_TYPE_BOOLEAN, + }, +}; + +static struct v4l2_queryctrl msp_qctrl_sound_processing[] = { + { + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, },{ .id = V4L2_CID_AUDIO_BASS, .name = "Bass", @@ -465,6 +493,15 @@ static struct v4l2_queryctrl msp_qctrl[] = { .step = 65535/100, .default_value = 32768, .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_LOUDNESS, + .name = "Loudness", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + .type = V4L2_CTRL_TYPE_BOOLEAN, }, }; @@ -490,24 +527,36 @@ static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) struct msp_state *state = i2c_get_clientdata(client); switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = state->volume; + break; + case V4L2_CID_AUDIO_MUTE: ctrl->value = state->muted; break; case V4L2_CID_AUDIO_BALANCE: + if (!state->has_sound_processing) + return -EINVAL; ctrl->value = state->balance; break; case V4L2_CID_AUDIO_BASS: + if (!state->has_sound_processing) + return -EINVAL; ctrl->value = state->bass; break; case V4L2_CID_AUDIO_TREBLE: + if (!state->has_sound_processing) + return -EINVAL; ctrl->value = state->treble; break; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = state->volume; + case V4L2_CID_AUDIO_LOUDNESS: + if (!state->has_sound_processing) + return -EINVAL; + ctrl->value = state->loudness; break; default: @@ -521,6 +570,12 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) struct msp_state *state = i2c_get_clientdata(client); switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + state->volume = ctrl->value; + if (state->volume == 0) + state->balance = 32768; + break; + case V4L2_CID_AUDIO_MUTE: if (ctrl->value < 0 || ctrl->value >= 2) return -ERANGE; @@ -528,21 +583,27 @@ static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) break; case V4L2_CID_AUDIO_BASS: + if (!state->has_sound_processing) + return -EINVAL; state->bass = ctrl->value; break; case V4L2_CID_AUDIO_TREBLE: + if (!state->has_sound_processing) + return -EINVAL; state->treble = ctrl->value; break; - case V4L2_CID_AUDIO_BALANCE: - state->balance = ctrl->value; + case V4L2_CID_AUDIO_LOUDNESS: + if (!state->has_sound_processing) + return -EINVAL; + state->loudness = ctrl->value; break; - case V4L2_CID_AUDIO_VOLUME: - state->volume = ctrl->value; - if (state->volume == 0) - state->balance = 32768; + case V4L2_CID_AUDIO_BALANCE: + if (!state->has_sound_processing) + return -EINVAL; + state->balance = ctrl->value; break; default: @@ -628,13 +689,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_audio *va = arg; - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (state->muted) - va->flags |= VIDEO_AUDIO_MUTE; - + va->flags |= VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_MUTABLE; + if (state->has_sound_processing) + va->flags |= VIDEO_AUDIO_BALANCE | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; if (state->muted) va->flags |= VIDEO_AUDIO_MUTE; va->volume = state->volume; @@ -642,7 +701,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) va->bass = state->bass; va->treble = state->treble; - msp_any_detect_stereo(client); + if (state->opmode == OPMODE_AUTOSELECT) + msp_any_detect_stereo(client); va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); break; } @@ -666,15 +726,24 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOCSCHAN: { struct video_channel *vc = arg; + int update = 0; + v4l2_std_id std; + if (state->radio) + update = 1; state->radio = 0; if (vc->norm == VIDEO_MODE_PAL) - state->std = V4L2_STD_PAL; + std = V4L2_STD_PAL; else if (vc->norm == VIDEO_MODE_SECAM) - state->std = V4L2_STD_SECAM; + std = V4L2_STD_SECAM; else - state->std = V4L2_STD_NTSC; - msp_wake_thread(client); + std = V4L2_STD_NTSC; + if (std != state->std) { + state->std = std; + update = 1; + } + if (update) + msp_wake_thread(client); break; } @@ -699,10 +768,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_STD: { v4l2_std_id *id = arg; + int update = state->radio || state->std != *id; state->std = *id; state->radio = 0; - msp_wake_thread(client); + if (update) + msp_wake_thread(client); return 0; } @@ -808,7 +879,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner *vt = arg; - msp_any_detect_stereo(client); + if (state->opmode == OPMODE_AUTOSELECT) + msp_any_detect_stereo(client); vt->audmode = state->audmode; vt->rxsubchans = state->rxsubchans; vt->capability = V4L2_TUNER_CAP_STEREO | @@ -887,9 +959,16 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; int i; - for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) - if (qc->id && qc->id == msp_qctrl[i].id) { - memcpy(qc, &msp_qctrl[i], sizeof(*qc)); + for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++) + if (qc->id && qc->id == msp_qctrl_std[i].id) { + memcpy(qc, &msp_qctrl_std[i], sizeof(*qc)); + return 0; + } + if (!state->has_sound_processing) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++) + if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) { + memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc)); return 0; } return -EINVAL; @@ -902,13 +981,17 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return msp_set_ctrl(client, arg); case VIDIOC_LOG_STATUS: - msp_any_detect_stereo(client); + if (state->opmode == OPMODE_AUTOSELECT) + msp_any_detect_stereo(client); v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", client->name, state->rev1, state->rev2); - v4l_info(client, "Audio: volume %d balance %d bass %d treble %d%s\n", - state->volume, state->balance, - state->bass, state->treble, - state->muted ? " (muted)" : ""); + v4l_info(client, "Audio: volume %d%s\n", + state->volume, state->muted ? " (muted)" : ""); + if (state->has_sound_processing) { + v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", + state->balance, state->bass, state->treble, + state->loudness ? "on" : "off"); + } v4l_info(client, "Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); @@ -983,6 +1066,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->balance = 32768; /* 0db gain */ state->bass = 32768; state->treble = 32768; + state->loudness = 0; state->input = -1; state->muted = 0; state->i2s_mode = 0; @@ -1023,6 +1107,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) /* Has scart2 and scart3 inputs and scart2 output: not in stripped down products of the '3' family */ state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5; + /* Has scart2 a volume control? Not in pre-D revisions. */ + state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out; /* Has subwoofer output: not in pre-D revs and not in stripped down products */ state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 4ecbf56b008..14a425a6ff8 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -209,24 +209,10 @@ void msp3400c_setmode(struct i2c_client *client, int type) } } -/* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */ -static int msp3400c_best_video_sound(int rxsubchans) -{ - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - return V4L2_TUNER_MODE_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - return V4L2_TUNER_MODE_LANG1; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - return V4L2_TUNER_MODE_LANG2; - return V4L2_TUNER_MODE_MONO; -} - /* turn on/off nicam + stereo */ void msp3400c_setstereo(struct i2c_client *client, int mode) { - static char *strmode[] = { "0", "mono", "stereo", "3", - "lang1", "5", "6", "7", "lang2" - }; + static char *strmode[] = { "mono", "stereo", "lang2", "lang1" }; struct msp_state *state = i2c_get_clientdata(client); int nicam = 0; /* channel source: FM/AM or nicam */ int src = 0; @@ -244,7 +230,7 @@ void msp3400c_setstereo(struct i2c_client *client, int mode) switch (state->mode) { case MSP_MODE_FM_TERRA: v4l_dbg(1, client, "FM setstereo: %s\n", strmode[mode]); - msp3400c_setcarrier(client,state->second,state->main); + msp3400c_setcarrier(client, state->second, state->main); switch (mode) { case V4L2_TUNER_MODE_STEREO: msp_write_dsp(client, 0x000e, 0x3001); @@ -298,7 +284,7 @@ void msp3400c_setstereo(struct i2c_client *client, int mode) } /* switch audio */ - switch (msp3400c_best_video_sound(mode)) { + switch (mode) { case V4L2_TUNER_MODE_STEREO: src = 0x0020 | nicam; break; @@ -330,6 +316,9 @@ void msp3400c_setstereo(struct i2c_client *client, int mode) msp_write_dsp(client, 0x0009, src); msp_write_dsp(client, 0x000a, src); msp_write_dsp(client, 0x000b, src); + msp_write_dsp(client, 0x000c, src); + if (state->has_scart23_in_scart2_out) + msp_write_dsp(client, 0x0041, src); } } @@ -455,9 +444,9 @@ static void watch_stereo(struct i2c_client *client) struct msp_state *state = i2c_get_clientdata(client); if (autodetect_stereo(client)) { - if (state->stereo & V4L2_TUNER_MODE_STEREO) + if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); - else if (state->stereo & VIDEO_SOUND_LANG1) + else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1) msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); else msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); @@ -657,7 +646,7 @@ int msp3410d_thread(void *data) { struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); - int mode,val,i,std; + int val, i, std; v4l_dbg(1, client, "msp3410 daemon started\n"); @@ -687,10 +676,11 @@ int msp3410d_thread(void *data) goto restart; /* start autodetect */ - mode = msp_modus(client); - std = (state->std & V4L2_STD_NTSC) ? 0x20 : 1; - msp_write_dem(client, 0x30, mode); - msp_write_dem(client, 0x20, std); + std = 1; + if (state->std & V4L2_STD_NTSC) + std = 0x20; + else + msp_write_dem(client, 0x20, std); state->watch_stereo = 0; if (debug) @@ -703,7 +693,7 @@ int msp3410d_thread(void *data) } else { /* triggered autodetect */ for (;;) { - if (msp_sleep(state,100)) + if (msp_sleep(state, 100)) goto restart; /* check results */ diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 70327506f89..fb44eef5d51 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -63,6 +63,7 @@ struct msp_state { int has_ntsc_jp_d_k3; int has_scart4; int has_scart23_in_scart2_out; + int has_scart2_out_volume; int has_subwoofer; int has_sound_processing; int has_virtual_dolby_surround; @@ -72,7 +73,6 @@ struct msp_state { int opmode; int mode; v4l2_std_id std; - int stereo; int nicam_on; int acb; int in_scart; @@ -85,8 +85,8 @@ struct msp_state { int audmode; int rxsubchans; - int muted; - int volume, balance; + int volume, muted; + int balance, loudness; int bass, treble; /* thread */ |