diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2006-01-09 12:25:42 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@brturbo.com.br> | 2006-01-09 12:25:42 -0500 |
commit | a8bbf12ad8a8ad532cea0b67f0127ad90d336b04 (patch) | |
tree | bd8d9fb0888a7fe28b4795d7567c01ccf72b3c38 /drivers/media/video/cx25840/cx25840-core.c | |
parent | 3578d3dd0b1e468a44a76a83efe90476a854625d (diff) |
V4L/DVB (3249): Generalized cx25840 video/audio input handling
- Added VIDIOC_S_AUDIO to set the audio inputs separately.
- Removed AUDC_SET_INPUT.
- Made the video inputs much more general.
- Removed cardtype CID and replaced with a CID to enable
the PVR150 workaround. The cardtype is no longer necessary
with the general video input change.
- Update VIDIOC_LOG_STATUS output to show the video and
audio inputs separately.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Diffstat (limited to 'drivers/media/video/cx25840/cx25840-core.c')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 180 |
1 files changed, 93 insertions, 87 deletions
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index c2c1e856aa60..a897d6b7d708 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -115,8 +115,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask, | |||
115 | 115 | ||
116 | /* ----------------------------------------------------------------------- */ | 116 | /* ----------------------------------------------------------------------- */ |
117 | 117 | ||
118 | static int set_input(struct i2c_client *, enum cx25840_input); | 118 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, |
119 | static void input_change(struct i2c_client *); | 119 | enum cx25840_audio_input aud_input); |
120 | static void log_status(struct i2c_client *client); | 120 | static void log_status(struct i2c_client *client); |
121 | 121 | ||
122 | /* ----------------------------------------------------------------------- */ | 122 | /* ----------------------------------------------------------------------- */ |
@@ -195,10 +195,8 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw) | |||
195 | /* AC97 shift */ | 195 | /* AC97 shift */ |
196 | cx25840_write(client, 0x8cf, 0x0f); | 196 | cx25840_write(client, 0x8cf, 0x0f); |
197 | 197 | ||
198 | /* (re)set video input */ | 198 | /* (re)set input */ |
199 | set_input(client, state->input); | 199 | set_input(client, state->vid_input, state->aud_input); |
200 | /* (re)set audio input */ | ||
201 | cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input); | ||
202 | 200 | ||
203 | /* start microcontroller */ | 201 | /* start microcontroller */ |
204 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 202 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
@@ -223,7 +221,7 @@ static void input_change(struct i2c_client *client) | |||
223 | cx25840_write(client, 0x80b, 0x10); | 221 | cx25840_write(client, 0x80b, 0x10); |
224 | } else if (std & V4L2_STD_NTSC) { | 222 | } else if (std & V4L2_STD_NTSC) { |
225 | /* NTSC */ | 223 | /* NTSC */ |
226 | if (state->cardtype == CARDTYPE_PVR150_WORKAROUND) { | 224 | if (state->pvr150_workaround) { |
227 | /* Certain Hauppauge PVR150 models have a hardware bug | 225 | /* Certain Hauppauge PVR150 models have a hardware bug |
228 | that causes audio to drop out. For these models the | 226 | that causes audio to drop out. For these models the |
229 | audio standard must be set explicitly. | 227 | audio standard must be set explicitly. |
@@ -259,72 +257,68 @@ static void input_change(struct i2c_client *client) | |||
259 | } | 257 | } |
260 | } | 258 | } |
261 | 259 | ||
262 | static int set_input(struct i2c_client *client, enum cx25840_input input) | 260 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, |
261 | enum cx25840_audio_input aud_input) | ||
263 | { | 262 | { |
264 | struct cx25840_state *state = i2c_get_clientdata(client); | 263 | struct cx25840_state *state = i2c_get_clientdata(client); |
264 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && | ||
265 | vid_input <= CX25840_COMPOSITE8); | ||
266 | u8 reg; | ||
265 | 267 | ||
266 | cx25840_dbg("decoder set input (%d)\n", input); | 268 | cx25840_dbg("decoder set video input %d, audio input %d\n", |
269 | vid_input, aud_input); | ||
267 | 270 | ||
268 | switch (input) { | 271 | if (is_composite) { |
269 | case CX25840_TUNER: | 272 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); |
270 | cx25840_dbg("now setting Tuner input\n"); | 273 | } else { |
271 | 274 | int luma = vid_input & 0xf0; | |
272 | if (state->cardtype == CARDTYPE_PVR150 || | 275 | int chroma = vid_input & 0xf00; |
273 | state->cardtype == CARDTYPE_PVR150_WORKAROUND) { | ||
274 | /* CH_SEL_ADC2=1 */ | ||
275 | cx25840_and_or(client, 0x102, ~0x2, 0x02); | ||
276 | } | ||
277 | |||
278 | /* Video Input Control */ | ||
279 | if (state->cardtype == CARDTYPE_PG600) { | ||
280 | cx25840_write(client, 0x103, 0x11); | ||
281 | } else { | ||
282 | cx25840_write(client, 0x103, 0x46); | ||
283 | } | ||
284 | |||
285 | /* INPUT_MODE=0 */ | ||
286 | cx25840_and_or(client, 0x401, ~0x6, 0x00); | ||
287 | break; | ||
288 | |||
289 | case CX25840_COMPOSITE0: | ||
290 | case CX25840_COMPOSITE1: | ||
291 | cx25840_dbg("now setting Composite input\n"); | ||
292 | 276 | ||
293 | /* Video Input Control */ | 277 | if ((vid_input & ~0xff0) || |
294 | if (state->cardtype == CARDTYPE_PG600) { | 278 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || |
295 | cx25840_write(client, 0x103, 0x00); | 279 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { |
296 | } else { | 280 | cx25840_err("0x%04x is not a valid video input!\n", vid_input); |
297 | cx25840_write(client, 0x103, 0x02); | 281 | return -EINVAL; |
298 | } | 282 | } |
299 | 283 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); | |
300 | /* INPUT_MODE=0 */ | 284 | if (chroma >= CX25840_SVIDEO_CHROMA7) { |
301 | cx25840_and_or(client, 0x401, ~0x6, 0x00); | 285 | reg &= 0x3f; |
302 | break; | 286 | reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; |
303 | |||
304 | case CX25840_SVIDEO0: | ||
305 | case CX25840_SVIDEO1: | ||
306 | cx25840_dbg("now setting S-Video input\n"); | ||
307 | |||
308 | /* CH_SEL_ADC2=0 */ | ||
309 | cx25840_and_or(client, 0x102, ~0x2, 0x00); | ||
310 | |||
311 | /* Video Input Control */ | ||
312 | if (state->cardtype == CARDTYPE_PG600) { | ||
313 | cx25840_write(client, 0x103, 0x02); | ||
314 | } else { | 287 | } else { |
315 | cx25840_write(client, 0x103, 0x10); | 288 | reg &= 0xcf; |
289 | reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; | ||
316 | } | 290 | } |
291 | } | ||
317 | 292 | ||
318 | /* INPUT_MODE=1 */ | 293 | switch (aud_input) { |
319 | cx25840_and_or(client, 0x401, ~0x6, 0x02); | 294 | case CX25840_AUDIO_SERIAL: |
295 | /* do nothing, use serial audio input */ | ||
320 | break; | 296 | break; |
297 | case CX25840_AUDIO4: reg &= ~0x30; break; | ||
298 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; | ||
299 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; | ||
300 | case CX25840_AUDIO7: reg &= ~0xc0; break; | ||
301 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; | ||
321 | 302 | ||
322 | default: | 303 | default: |
323 | cx25840_err("%d is not a valid input!\n", input); | 304 | cx25840_err("0x%04x is not a valid audio input!\n", aud_input); |
324 | return -EINVAL; | 305 | return -EINVAL; |
325 | } | 306 | } |
326 | 307 | ||
327 | state->input = input; | 308 | cx25840_write(client, 0x103, reg); |
309 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ | ||
310 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | ||
311 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | ||
312 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | ||
313 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ | ||
314 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) | ||
315 | cx25840_and_or(client, 0x102, ~0x4, 4); | ||
316 | else | ||
317 | cx25840_and_or(client, 0x102, ~0x4, 0); | ||
318 | |||
319 | state->vid_input = vid_input; | ||
320 | state->aud_input = aud_input; | ||
321 | cx25840_audio_set_path(client); | ||
328 | input_change(client); | 322 | input_change(client); |
329 | return 0; | 323 | return 0; |
330 | } | 324 | } |
@@ -395,18 +389,9 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
395 | struct cx25840_state *state = i2c_get_clientdata(client); | 389 | struct cx25840_state *state = i2c_get_clientdata(client); |
396 | 390 | ||
397 | switch (ctrl->id) { | 391 | switch (ctrl->id) { |
398 | case CX25840_CID_CARDTYPE: | 392 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: |
399 | switch (ctrl->value) { | 393 | state->pvr150_workaround = ctrl->value; |
400 | case CARDTYPE_PVR150: | 394 | set_input(client, state->vid_input, state->aud_input); |
401 | case CARDTYPE_PVR150_WORKAROUND: | ||
402 | case CARDTYPE_PG600: | ||
403 | state->cardtype = ctrl->value; | ||
404 | break; | ||
405 | default: | ||
406 | return -ERANGE; | ||
407 | } | ||
408 | |||
409 | set_input(client, state->input); | ||
410 | break; | 395 | break; |
411 | 396 | ||
412 | case V4L2_CID_BRIGHTNESS: | 397 | case V4L2_CID_BRIGHTNESS: |
@@ -465,8 +450,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | |||
465 | struct cx25840_state *state = i2c_get_clientdata(client); | 450 | struct cx25840_state *state = i2c_get_clientdata(client); |
466 | 451 | ||
467 | switch (ctrl->id) { | 452 | switch (ctrl->id) { |
468 | case CX25840_CID_CARDTYPE: | 453 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: |
469 | ctrl->value = state->cardtype; | 454 | ctrl->value = state->pvr150_workaround; |
470 | break; | 455 | break; |
471 | case V4L2_CID_BRIGHTNESS: | 456 | case V4L2_CID_BRIGHTNESS: |
472 | ctrl->value = cx25840_read(client, 0x414) + 128; | 457 | ctrl->value = cx25840_read(client, 0x414) + 128; |
@@ -615,7 +600,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
615 | return cx25840_vbi(client, cmd, arg); | 600 | return cx25840_vbi(client, cmd, arg); |
616 | 601 | ||
617 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | 602 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: |
618 | case AUDC_SET_INPUT: | ||
619 | result = cx25840_audio(client, cmd, arg); | 603 | result = cx25840_audio(client, cmd, arg); |
620 | break; | 604 | break; |
621 | 605 | ||
@@ -652,13 +636,30 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
652 | break; | 636 | break; |
653 | 637 | ||
654 | case VIDIOC_G_INPUT: | 638 | case VIDIOC_G_INPUT: |
655 | *(int *)arg = state->input; | 639 | *(int *)arg = state->vid_input; |
656 | break; | 640 | break; |
657 | 641 | ||
658 | case VIDIOC_S_INPUT: | 642 | case VIDIOC_S_INPUT: |
659 | result = set_input(client, *(int *)arg); | 643 | result = set_input(client, *(enum cx25840_video_input *)arg, state->aud_input); |
660 | break; | 644 | break; |
661 | 645 | ||
646 | case VIDIOC_S_AUDIO: | ||
647 | { | ||
648 | struct v4l2_audio *input = arg; | ||
649 | |||
650 | result = set_input(client, state->vid_input, input->index); | ||
651 | break; | ||
652 | } | ||
653 | |||
654 | case VIDIOC_G_AUDIO: | ||
655 | { | ||
656 | struct v4l2_audio *input = arg; | ||
657 | |||
658 | memset(input, 0, sizeof(*input)); | ||
659 | input->index = state->aud_input; | ||
660 | break; | ||
661 | } | ||
662 | |||
662 | case VIDIOC_S_FREQUENCY: | 663 | case VIDIOC_S_FREQUENCY: |
663 | input_change(client); | 664 | input_change(client); |
664 | break; | 665 | break; |
@@ -801,10 +802,10 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
801 | 802 | ||
802 | i2c_set_clientdata(client, state); | 803 | i2c_set_clientdata(client, state); |
803 | memset(state, 0, sizeof(struct cx25840_state)); | 804 | memset(state, 0, sizeof(struct cx25840_state)); |
804 | state->input = CX25840_TUNER; | 805 | state->vid_input = CX25840_COMPOSITE7; |
806 | state->aud_input = CX25840_AUDIO8; | ||
805 | state->audclk_freq = 48000; | 807 | state->audclk_freq = 48000; |
806 | state->audio_input = AUDIO_TUNER; | 808 | state->pvr150_workaround = 0; |
807 | state->cardtype = CARDTYPE_PVR150; | ||
808 | 809 | ||
809 | cx25840_initialize(client, 1); | 810 | cx25840_initialize(client, 1); |
810 | 811 | ||
@@ -888,6 +889,8 @@ static void log_status(struct i2c_client *client) | |||
888 | u8 pref_mode = cx25840_read(client, 0x809); | 889 | u8 pref_mode = cx25840_read(client, 0x809); |
889 | u8 afc0 = cx25840_read(client, 0x80b); | 890 | u8 afc0 = cx25840_read(client, 0x80b); |
890 | u8 mute_ctl = cx25840_read(client, 0x8d3); | 891 | u8 mute_ctl = cx25840_read(client, 0x8d3); |
892 | int vid_input = state->vid_input; | ||
893 | int aud_input = state->aud_input; | ||
891 | char *p; | 894 | char *p; |
892 | 895 | ||
893 | cx25840_info("Video signal: %spresent\n", | 896 | cx25840_info("Video signal: %spresent\n", |
@@ -997,16 +1000,19 @@ static void log_status(struct i2c_client *client) | |||
997 | cx25840_info("Specified standard: %s\n", | 1000 | cx25840_info("Specified standard: %s\n", |
998 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | 1001 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); |
999 | 1002 | ||
1000 | switch (state->input) { | 1003 | if (vid_input >= CX25840_COMPOSITE1 && |
1001 | case CX25840_COMPOSITE0: p = "Composite 0"; break; | 1004 | vid_input <= CX25840_COMPOSITE8) { |
1002 | case CX25840_COMPOSITE1: p = "Composite 1"; break; | 1005 | cx25840_info("Specified video input: Composite %d\n", |
1003 | case CX25840_SVIDEO0: p = "S-Video 0"; break; | 1006 | vid_input - CX25840_COMPOSITE1 + 1); |
1004 | case CX25840_SVIDEO1: p = "S-Video 1"; break; | 1007 | } else { |
1005 | case CX25840_TUNER: p = "Tuner"; break; | 1008 | cx25840_info("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", |
1009 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); | ||
1010 | } | ||
1011 | if (aud_input) { | ||
1012 | cx25840_info("Specified audio input: Tuner (In%d)\n", aud_input); | ||
1013 | } else { | ||
1014 | cx25840_info("Specified audio input: External\n"); | ||
1006 | } | 1015 | } |
1007 | cx25840_info("Specified input: %s\n", p); | ||
1008 | cx25840_info("Specified audio input: %s\n", | ||
1009 | state->audio_input == 0 ? "Tuner" : "External"); | ||
1010 | 1016 | ||
1011 | cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq); | 1017 | cx25840_info("Specified audioclock freq: %d Hz\n", state->audclk_freq); |
1012 | 1018 | ||