diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-01-24 09:31:36 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:30:13 -0500 |
commit | 6330079fc6df4a0829f952b73c4d4999e56034f8 (patch) | |
tree | 936d9f393e49fc986f7383b757f69a4529f5bf12 | |
parent | 09a99959180d25f4e5070f902e3adc1b20439cd6 (diff) |
[ALSA] hda-codec - Fix handling of multiple capture streams
Fixed the bug that multiple capture streams conflict on Realtek codec
routines.
Also, this adds a framework to enable the alternative playback stream,
e.g. for VoIP. It's not fully implemented yet, though.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6f652afd3cbe..c08852acd07e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -220,6 +220,8 @@ struct alc_spec { | |||
220 | char *stream_name_analog; /* analog PCM stream */ | 220 | char *stream_name_analog; /* analog PCM stream */ |
221 | struct hda_pcm_stream *stream_analog_playback; | 221 | struct hda_pcm_stream *stream_analog_playback; |
222 | struct hda_pcm_stream *stream_analog_capture; | 222 | struct hda_pcm_stream *stream_analog_capture; |
223 | struct hda_pcm_stream *stream_analog_alt_playback; | ||
224 | struct hda_pcm_stream *stream_analog_alt_capture; | ||
223 | 225 | ||
224 | char *stream_name_digital; /* digital PCM stream */ | 226 | char *stream_name_digital; /* digital PCM stream */ |
225 | struct hda_pcm_stream *stream_digital_playback; | 227 | struct hda_pcm_stream *stream_digital_playback; |
@@ -230,6 +232,7 @@ struct alc_spec { | |||
230 | * max_channels, dacs must be set | 232 | * max_channels, dacs must be set |
231 | * dig_out_nid and hp_nid are optional | 233 | * dig_out_nid and hp_nid are optional |
232 | */ | 234 | */ |
235 | hda_nid_t alt_dac_nid; | ||
233 | 236 | ||
234 | /* capture */ | 237 | /* capture */ |
235 | unsigned int num_adc_nids; | 238 | unsigned int num_adc_nids; |
@@ -2370,7 +2373,7 @@ static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
2370 | /* | 2373 | /* |
2371 | * Analog capture | 2374 | * Analog capture |
2372 | */ | 2375 | */ |
2373 | static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | 2376 | static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
2374 | struct hda_codec *codec, | 2377 | struct hda_codec *codec, |
2375 | unsigned int stream_tag, | 2378 | unsigned int stream_tag, |
2376 | unsigned int format, | 2379 | unsigned int format, |
@@ -2378,18 +2381,18 @@ static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
2378 | { | 2381 | { |
2379 | struct alc_spec *spec = codec->spec; | 2382 | struct alc_spec *spec = codec->spec; |
2380 | 2383 | ||
2381 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2384 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2382 | stream_tag, 0, format); | 2385 | stream_tag, 0, format); |
2383 | return 0; | 2386 | return 0; |
2384 | } | 2387 | } |
2385 | 2388 | ||
2386 | static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | 2389 | static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, |
2387 | struct hda_codec *codec, | 2390 | struct hda_codec *codec, |
2388 | struct snd_pcm_substream *substream) | 2391 | struct snd_pcm_substream *substream) |
2389 | { | 2392 | { |
2390 | struct alc_spec *spec = codec->spec; | 2393 | struct alc_spec *spec = codec->spec; |
2391 | 2394 | ||
2392 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2395 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2393 | 0, 0, 0); | 2396 | 0, 0, 0); |
2394 | return 0; | 2397 | return 0; |
2395 | } | 2398 | } |
@@ -2410,13 +2413,27 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { | |||
2410 | }; | 2413 | }; |
2411 | 2414 | ||
2412 | static struct hda_pcm_stream alc880_pcm_analog_capture = { | 2415 | static struct hda_pcm_stream alc880_pcm_analog_capture = { |
2413 | .substreams = 2, | 2416 | .substreams = 1, |
2417 | .channels_min = 2, | ||
2418 | .channels_max = 2, | ||
2419 | /* NID is set in alc_build_pcms */ | ||
2420 | }; | ||
2421 | |||
2422 | static struct hda_pcm_stream alc880_pcm_analog_alt_playback = { | ||
2423 | .substreams = 1, | ||
2424 | .channels_min = 2, | ||
2425 | .channels_max = 2, | ||
2426 | /* NID is set in alc_build_pcms */ | ||
2427 | }; | ||
2428 | |||
2429 | static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { | ||
2430 | .substreams = 2, /* can be overridden */ | ||
2414 | .channels_min = 2, | 2431 | .channels_min = 2, |
2415 | .channels_max = 2, | 2432 | .channels_max = 2, |
2416 | /* NID is set in alc_build_pcms */ | 2433 | /* NID is set in alc_build_pcms */ |
2417 | .ops = { | 2434 | .ops = { |
2418 | .prepare = alc880_capture_pcm_prepare, | 2435 | .prepare = alc880_alt_capture_pcm_prepare, |
2419 | .cleanup = alc880_capture_pcm_cleanup | 2436 | .cleanup = alc880_alt_capture_pcm_cleanup |
2420 | }, | 2437 | }, |
2421 | }; | 2438 | }; |
2422 | 2439 | ||
@@ -2440,7 +2457,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { | |||
2440 | }; | 2457 | }; |
2441 | 2458 | ||
2442 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ | 2459 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ |
2443 | static struct hda_pcm_stream alc_pcm_null_playback = { | 2460 | static struct hda_pcm_stream alc_pcm_null_stream = { |
2444 | .substreams = 0, | 2461 | .substreams = 0, |
2445 | .channels_min = 0, | 2462 | .channels_min = 0, |
2446 | .channels_max = 0, | 2463 | .channels_max = 0, |
@@ -2497,17 +2514,32 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
2497 | * model, configure a second analog capture-only PCM. | 2514 | * model, configure a second analog capture-only PCM. |
2498 | */ | 2515 | */ |
2499 | /* Additional Analaog capture for index #2 */ | 2516 | /* Additional Analaog capture for index #2 */ |
2500 | if (spec->num_adc_nids > 1 && spec->stream_analog_capture && | 2517 | if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) || |
2501 | spec->adc_nids) { | 2518 | (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) { |
2502 | codec->num_pcms = 3; | 2519 | codec->num_pcms = 3; |
2503 | info = spec->pcm_rec + 2; | 2520 | info = spec->pcm_rec + 2; |
2504 | info->name = spec->stream_name_analog; | 2521 | info->name = spec->stream_name_analog; |
2505 | /* No playback stream for second PCM */ | 2522 | if (spec->alt_dac_nid) { |
2506 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | 2523 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
2507 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | 2524 | *spec->stream_analog_alt_playback; |
2508 | if (spec->stream_analog_capture) { | 2525 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
2509 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | 2526 | spec->alt_dac_nid; |
2510 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | 2527 | } else { |
2528 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
2529 | alc_pcm_null_stream; | ||
2530 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
2531 | } | ||
2532 | if (spec->num_adc_nids > 1) { | ||
2533 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2534 | *spec->stream_analog_alt_capture; | ||
2535 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
2536 | spec->adc_nids[1]; | ||
2537 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = | ||
2538 | spec->num_adc_nids - 1; | ||
2539 | } else { | ||
2540 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2541 | alc_pcm_null_stream; | ||
2542 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; | ||
2511 | } | 2543 | } |
2512 | } | 2544 | } |
2513 | 2545 | ||
@@ -3615,6 +3647,7 @@ static int patch_alc880(struct hda_codec *codec) | |||
3615 | spec->stream_name_analog = "ALC880 Analog"; | 3647 | spec->stream_name_analog = "ALC880 Analog"; |
3616 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 3648 | spec->stream_analog_playback = &alc880_pcm_analog_playback; |
3617 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | 3649 | spec->stream_analog_capture = &alc880_pcm_analog_capture; |
3650 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
3618 | 3651 | ||
3619 | spec->stream_name_digital = "ALC880 Digital"; | 3652 | spec->stream_name_digital = "ALC880 Digital"; |
3620 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 3653 | spec->stream_digital_playback = &alc880_pcm_digital_playback; |
@@ -4527,17 +4560,8 @@ static struct hda_verb alc260_test_init_verbs[] = { | |||
4527 | }; | 4560 | }; |
4528 | #endif | 4561 | #endif |
4529 | 4562 | ||
4530 | static struct hda_pcm_stream alc260_pcm_analog_playback = { | 4563 | #define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback |
4531 | .substreams = 1, | 4564 | #define alc260_pcm_analog_capture alc880_pcm_analog_capture |
4532 | .channels_min = 2, | ||
4533 | .channels_max = 2, | ||
4534 | }; | ||
4535 | |||
4536 | static struct hda_pcm_stream alc260_pcm_analog_capture = { | ||
4537 | .substreams = 1, | ||
4538 | .channels_min = 2, | ||
4539 | .channels_max = 2, | ||
4540 | }; | ||
4541 | 4565 | ||
4542 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback | 4566 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback |
4543 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture | 4567 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture |
@@ -6204,6 +6228,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
6204 | spec->stream_name_analog = "ALC882 Analog"; | 6228 | spec->stream_name_analog = "ALC882 Analog"; |
6205 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6229 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
6206 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6230 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
6231 | /* FIXME: setup DAC5 */ | ||
6232 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ | ||
6233 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
6207 | 6234 | ||
6208 | spec->stream_name_digital = "ALC882 Digital"; | 6235 | spec->stream_name_digital = "ALC882 Digital"; |
6209 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 6236 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
@@ -7409,6 +7436,7 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
7409 | /* pcm configuration: identiacal with ALC880 */ | 7436 | /* pcm configuration: identiacal with ALC880 */ |
7410 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback | 7437 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback |
7411 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture | 7438 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture |
7439 | #define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
7412 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback | 7440 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback |
7413 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture | 7441 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture |
7414 | 7442 | ||
@@ -7894,6 +7922,7 @@ static int patch_alc883(struct hda_codec *codec) | |||
7894 | spec->stream_name_analog = "ALC883 Analog"; | 7922 | spec->stream_name_analog = "ALC883 Analog"; |
7895 | spec->stream_analog_playback = &alc883_pcm_analog_playback; | 7923 | spec->stream_analog_playback = &alc883_pcm_analog_playback; |
7896 | spec->stream_analog_capture = &alc883_pcm_analog_capture; | 7924 | spec->stream_analog_capture = &alc883_pcm_analog_capture; |
7925 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; | ||
7897 | 7926 | ||
7898 | spec->stream_name_digital = "ALC883 Digital"; | 7927 | spec->stream_name_digital = "ALC883 Digital"; |
7899 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 7928 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
@@ -9821,6 +9850,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) | |||
9821 | /* pcm configuration: identiacal with ALC880 */ | 9850 | /* pcm configuration: identiacal with ALC880 */ |
9822 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback | 9851 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback |
9823 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture | 9852 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture |
9853 | #define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
9824 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback | 9854 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback |
9825 | 9855 | ||
9826 | /* | 9856 | /* |
@@ -10022,6 +10052,7 @@ static int patch_alc268(struct hda_codec *codec) | |||
10022 | spec->stream_name_analog = "ALC268 Analog"; | 10052 | spec->stream_name_analog = "ALC268 Analog"; |
10023 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 10053 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
10024 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 10054 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
10055 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | ||
10025 | 10056 | ||
10026 | spec->stream_name_digital = "ALC268 Digital"; | 10057 | spec->stream_name_digital = "ALC268 Digital"; |
10027 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | 10058 | spec->stream_digital_playback = &alc268_pcm_digital_playback; |