diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2007-08-05 07:00:36 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-09 21:04:55 -0400 |
commit | 87410dab1238623e082e9a78a62f1bbeb6c475e3 (patch) | |
tree | 521977ac3c7c91b9d97616452047bcddfd066279 /drivers/media/video/cx25840 | |
parent | 372978055dd564d97ca1b4099c99296eaff1fe19 (diff) |
V4L/DVB (5997): cx25840: fix audio mute handling and reporting
Audio muting for the tuner input was implemented by stopping the
audio microcontroller and restarting it on unmute. However, it
appears that this method can actually crash the audio firmware.
It's rare and seems to happen with NTSC only.
It has been reimplemented by setting to volume to 0. In addition, the
reporting of the mute state has been improved as well: it used to be
impossible to detect whether the audio was muted by the user or if it
was muted due to the microcontroller trying to detect the audio
standard. This is now clearly stated.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 53 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 6 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 1 |
3 files changed, 37 insertions, 23 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index f897c1ebd5f3..f93b5160bb4f 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -194,19 +194,34 @@ void cx25840_audio_set_path(struct i2c_client *client) | |||
194 | 194 | ||
195 | static int get_volume(struct i2c_client *client) | 195 | static int get_volume(struct i2c_client *client) |
196 | { | 196 | { |
197 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
198 | int vol; | ||
199 | |||
200 | if (state->unmute_volume >= 0) | ||
201 | return state->unmute_volume; | ||
202 | |||
197 | /* Volume runs +18dB to -96dB in 1/2dB steps | 203 | /* Volume runs +18dB to -96dB in 1/2dB steps |
198 | * change to fit the msp3400 -114dB to +12dB range */ | 204 | * change to fit the msp3400 -114dB to +12dB range */ |
199 | 205 | ||
200 | /* check PATH1_VOLUME */ | 206 | /* check PATH1_VOLUME */ |
201 | int vol = 228 - cx25840_read(client, 0x8d4); | 207 | vol = 228 - cx25840_read(client, 0x8d4); |
202 | vol = (vol / 2) + 23; | 208 | vol = (vol / 2) + 23; |
203 | return vol << 9; | 209 | return vol << 9; |
204 | } | 210 | } |
205 | 211 | ||
206 | static void set_volume(struct i2c_client *client, int volume) | 212 | static void set_volume(struct i2c_client *client, int volume) |
207 | { | 213 | { |
208 | /* First convert the volume to msp3400 values (0-127) */ | 214 | struct cx25840_state *state = i2c_get_clientdata(client); |
209 | int vol = volume >> 9; | 215 | int vol; |
216 | |||
217 | if (state->unmute_volume >= 0) { | ||
218 | state->unmute_volume = volume; | ||
219 | return; | ||
220 | } | ||
221 | |||
222 | /* Convert the volume to msp3400 values (0-127) */ | ||
223 | vol = volume >> 9; | ||
224 | |||
210 | /* now scale it up to cx25840 values | 225 | /* now scale it up to cx25840 values |
211 | * -114dB to -96dB maps to 0 | 226 | * -114dB to -96dB maps to 0 |
212 | * this should be 19, but in my testing that was 4dB too loud */ | 227 | * this should be 19, but in my testing that was 4dB too loud */ |
@@ -284,30 +299,26 @@ static void set_balance(struct i2c_client *client, int balance) | |||
284 | 299 | ||
285 | static int get_mute(struct i2c_client *client) | 300 | static int get_mute(struct i2c_client *client) |
286 | { | 301 | { |
287 | /* check SRC1_MUTE_EN */ | 302 | struct cx25840_state *state = i2c_get_clientdata(client); |
288 | return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; | 303 | |
304 | return state->unmute_volume >= 0; | ||
289 | } | 305 | } |
290 | 306 | ||
291 | static void set_mute(struct i2c_client *client, int mute) | 307 | static void set_mute(struct i2c_client *client, int mute) |
292 | { | 308 | { |
293 | struct cx25840_state *state = i2c_get_clientdata(client); | 309 | struct cx25840_state *state = i2c_get_clientdata(client); |
294 | 310 | ||
295 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | 311 | if (mute && state->unmute_volume == -1) { |
296 | /* Must turn off microcontroller in order to mute sound. | 312 | int vol = get_volume(client); |
297 | * Not sure if this is the best method, but it does work. | 313 | |
298 | * If the microcontroller is running, then it will undo any | 314 | set_volume(client, 0); |
299 | * changes to the mute register. */ | 315 | state->unmute_volume = vol; |
300 | if (mute) { | 316 | } |
301 | /* disable microcontroller */ | 317 | else if (!mute && state->unmute_volume != -1) { |
302 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | 318 | int vol = state->unmute_volume; |
303 | cx25840_write(client, 0x8d3, 0x1f); | 319 | |
304 | } else { | 320 | state->unmute_volume = -1; |
305 | /* enable microcontroller */ | 321 | set_volume(client, vol); |
306 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
307 | } | ||
308 | } else { | ||
309 | /* SRC1_MUTE_EN */ | ||
310 | cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); | ||
311 | } | 322 | } |
312 | } | 323 | } |
313 | 324 | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 9f99007d389b..65ad7943dd9a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -915,6 +915,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
915 | state->audclk_freq = 48000; | 915 | state->audclk_freq = 48000; |
916 | state->pvr150_workaround = 0; | 916 | state->pvr150_workaround = 0; |
917 | state->audmode = V4L2_TUNER_MODE_LANG1; | 917 | state->audmode = V4L2_TUNER_MODE_LANG1; |
918 | state->unmute_volume = -1; | ||
918 | state->vbi_line_offset = 8; | 919 | state->vbi_line_offset = 8; |
919 | state->id = id; | 920 | state->id = id; |
920 | state->rev = device_id; | 921 | state->rev = device_id; |
@@ -1066,9 +1067,10 @@ static void log_audio_status(struct i2c_client *client) | |||
1066 | } | 1067 | } |
1067 | v4l_info(client, "Detected audio standard: %s\n", p); | 1068 | v4l_info(client, "Detected audio standard: %s\n", p); |
1068 | v4l_info(client, "Audio muted: %s\n", | 1069 | v4l_info(client, "Audio muted: %s\n", |
1069 | (mute_ctl & 0x2) ? "yes" : "no"); | 1070 | (state->unmute_volume >= 0) ? "yes" : "no"); |
1070 | v4l_info(client, "Audio microcontroller: %s\n", | 1071 | v4l_info(client, "Audio microcontroller: %s\n", |
1071 | (download_ctl & 0x10) ? "running" : "stopped"); | 1072 | (download_ctl & 0x10) ? |
1073 | ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); | ||
1072 | 1074 | ||
1073 | switch (audio_config >> 4) { | 1075 | switch (audio_config >> 4) { |
1074 | case 0x00: p = "undefined"; break; | 1076 | case 0x00: p = "undefined"; break; |
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 8c1fbd9b87c1..86e2edfc4941 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -42,6 +42,7 @@ struct cx25840_state { | |||
42 | enum cx25840_audio_input aud_input; | 42 | enum cx25840_audio_input aud_input; |
43 | u32 audclk_freq; | 43 | u32 audclk_freq; |
44 | int audmode; | 44 | int audmode; |
45 | int unmute_volume; /* -1 if not muted */ | ||
45 | int vbi_line_offset; | 46 | int vbi_line_offset; |
46 | u32 id; | 47 | u32 id; |
47 | u32 rev; | 48 | u32 rev; |