aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-02-12 12:37:26 -0500
committerTakashi Iwai <tiwai@suse.de>2008-04-24 06:00:10 -0400
commit9a08160bdbe3148a405f72798f76e2a5d30bd243 (patch)
tree33b6785feb1fda1d381a74ef19eb26c983650749 /sound/pci/hda
parentf6c7e5461e9046445d50c5c7a9a4587824239623 (diff)
[ALSA] hda-codec - Add "IEC958 Default PCM" switch
Added a new mixer switch to enable/disable the sharing of the default PCM stream with analog and SPDIF outputs. When "IEC958 Default PCM" switch is on, the PCM stream is routed both to analog and SPDIF outputs. This is the behavior in the earlier version. Turning this switch off has a merit for some codecs, though. Some codec chips don't support 24bit formats for SPDIF but only for analog outputs. In this case, you can use 24bit format by disabling this switch. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c73
-rw-r--r--sound/pci/hda/hda_local.h13
-rw-r--r--sound/pci/hda/patch_analog.c8
-rw-r--r--sound/pci/hda/patch_cmedia.c8
-rw-r--r--sound/pci/hda/patch_conexant.c8
-rw-r--r--sound/pci/hda/patch_realtek.c8
-rw-r--r--sound/pci/hda/patch_sigmatel.c8
-rw-r--r--sound/pci/hda/patch_via.c8
8 files changed, 123 insertions, 11 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index af2c8943b303..853e5c786c37 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1533,6 +1533,43 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid)
1533} 1533}
1534 1534
1535/* 1535/*
1536 * SPDIF sharing with analog output
1537 */
1538static int spdif_share_sw_get(struct snd_kcontrol *kcontrol,
1539 struct snd_ctl_elem_value *ucontrol)
1540{
1541 struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
1542 ucontrol->value.integer.value[0] = mout->share_spdif;
1543 return 0;
1544}
1545
1546static int spdif_share_sw_put(struct snd_kcontrol *kcontrol,
1547 struct snd_ctl_elem_value *ucontrol)
1548{
1549 struct hda_multi_out *mout = snd_kcontrol_chip(kcontrol);
1550 mout->share_spdif = !!ucontrol->value.integer.value[0];
1551 return 0;
1552}
1553
1554static struct snd_kcontrol_new spdif_share_sw = {
1555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1556 .name = "IEC958 Default PCM Playback Switch",
1557 .info = snd_ctl_boolean_mono_info,
1558 .get = spdif_share_sw_get,
1559 .put = spdif_share_sw_put,
1560};
1561
1562int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
1563 struct hda_multi_out *mout)
1564{
1565 if (!mout->dig_out_nid)
1566 return 0;
1567 /* ATTENTION: here mout is passed as private_data, instead of codec */
1568 return snd_ctl_add(codec->bus->card,
1569 snd_ctl_new1(&spdif_share_sw, mout));
1570}
1571
1572/*
1536 * SPDIF input 1573 * SPDIF input
1537 */ 1574 */
1538 1575
@@ -2557,9 +2594,36 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec,
2557 */ 2594 */
2558int snd_hda_multi_out_analog_open(struct hda_codec *codec, 2595int snd_hda_multi_out_analog_open(struct hda_codec *codec,
2559 struct hda_multi_out *mout, 2596 struct hda_multi_out *mout,
2560 struct snd_pcm_substream *substream) 2597 struct snd_pcm_substream *substream,
2561{ 2598 struct hda_pcm_stream *hinfo)
2562 substream->runtime->hw.channels_max = mout->max_channels; 2599{
2600 struct snd_pcm_runtime *runtime = substream->runtime;
2601 runtime->hw.channels_max = mout->max_channels;
2602 if (mout->dig_out_nid) {
2603 if (!mout->analog_rates) {
2604 mout->analog_rates = hinfo->rates;
2605 mout->analog_formats = hinfo->formats;
2606 mout->analog_maxbps = hinfo->maxbps;
2607 } else {
2608 runtime->hw.rates = mout->analog_rates;
2609 runtime->hw.formats = mout->analog_formats;
2610 hinfo->maxbps = mout->analog_maxbps;
2611 }
2612 if (!mout->spdif_rates) {
2613 snd_hda_query_supported_pcm(codec, mout->dig_out_nid,
2614 &mout->spdif_rates,
2615 &mout->spdif_formats,
2616 &mout->spdif_maxbps);
2617 }
2618 mutex_lock(&codec->spdif_mutex);
2619 if (mout->share_spdif) {
2620 runtime->hw.rates &= mout->spdif_rates;
2621 runtime->hw.formats &= mout->spdif_formats;
2622 if (mout->spdif_maxbps < hinfo->maxbps)
2623 hinfo->maxbps = mout->spdif_maxbps;
2624 }
2625 }
2626 mutex_unlock(&codec->spdif_mutex);
2563 return snd_pcm_hw_constraint_step(substream->runtime, 0, 2627 return snd_pcm_hw_constraint_step(substream->runtime, 0,
2564 SNDRV_PCM_HW_PARAM_CHANNELS, 2); 2628 SNDRV_PCM_HW_PARAM_CHANNELS, 2);
2565} 2629}
@@ -2579,7 +2643,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
2579 int i; 2643 int i;
2580 2644
2581 mutex_lock(&codec->spdif_mutex); 2645 mutex_lock(&codec->spdif_mutex);
2582 if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { 2646 if (mout->dig_out_nid && mout->share_spdif &&
2647 mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
2583 if (chs == 2 && 2648 if (chs == 2 &&
2584 snd_hda_is_supported_format(codec, mout->dig_out_nid, 2649 snd_hda_is_supported_format(codec, mout->dig_out_nid,
2585 format) && 2650 format) &&
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index ad0014ab71f9..ce2ad42a8a8a 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -228,8 +228,18 @@ struct hda_multi_out {
228 int max_channels; /* currently supported analog channels */ 228 int max_channels; /* currently supported analog channels */
229 int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ 229 int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */
230 int no_share_stream; /* don't share a stream with multiple pins */ 230 int no_share_stream; /* don't share a stream with multiple pins */
231 int share_spdif; /* share SPDIF pin */
232 /* PCM information for both analog and SPDIF DACs */
233 unsigned int analog_rates;
234 unsigned int analog_maxbps;
235 u64 analog_formats;
236 unsigned int spdif_rates;
237 unsigned int spdif_maxbps;
238 u64 spdif_formats;
231}; 239};
232 240
241int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
242 struct hda_multi_out *mout);
233int snd_hda_multi_out_dig_open(struct hda_codec *codec, 243int snd_hda_multi_out_dig_open(struct hda_codec *codec,
234 struct hda_multi_out *mout); 244 struct hda_multi_out *mout);
235int snd_hda_multi_out_dig_close(struct hda_codec *codec, 245int snd_hda_multi_out_dig_close(struct hda_codec *codec,
@@ -241,7 +251,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
241 struct snd_pcm_substream *substream); 251 struct snd_pcm_substream *substream);
242int snd_hda_multi_out_analog_open(struct hda_codec *codec, 252int snd_hda_multi_out_analog_open(struct hda_codec *codec,
243 struct hda_multi_out *mout, 253 struct hda_multi_out *mout,
244 struct snd_pcm_substream *substream); 254 struct snd_pcm_substream *substream,
255 struct hda_pcm_stream *hinfo);
245int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, 256int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
246 struct hda_multi_out *mout, 257 struct hda_multi_out *mout,
247 unsigned int stream_tag, 258 unsigned int stream_tag,
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 266c35e32b64..1f2102860fe8 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -171,6 +171,11 @@ static int ad198x_build_controls(struct hda_codec *codec)
171 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 171 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
172 if (err < 0) 172 if (err < 0)
173 return err; 173 return err;
174 err = snd_hda_create_spdif_share_sw(codec,
175 &spec->multiout);
176 if (err < 0)
177 return err;
178 spec->multiout.share_spdif = 1;
174 } 179 }
175 if (spec->dig_in_nid) { 180 if (spec->dig_in_nid) {
176 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 181 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -217,7 +222,8 @@ static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
217 struct snd_pcm_substream *substream) 222 struct snd_pcm_substream *substream)
218{ 223{
219 struct ad198x_spec *spec = codec->spec; 224 struct ad198x_spec *spec = codec->spec;
220 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 225 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
226 hinfo);
221} 227}
222 228
223static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 229static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 99ce74b4e9fc..9794d4166ae4 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -329,6 +329,11 @@ static int cmi9880_build_controls(struct hda_codec *codec)
329 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 329 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
330 if (err < 0) 330 if (err < 0)
331 return err; 331 return err;
332 err = snd_hda_create_spdif_share_sw(codec,
333 &spec->multiout);
334 if (err < 0)
335 return err;
336 spec->multiout.share_spdif = 1;
332 } 337 }
333 if (spec->dig_in_nid) { 338 if (spec->dig_in_nid) {
334 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 339 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -432,7 +437,8 @@ static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo,
432 struct snd_pcm_substream *substream) 437 struct snd_pcm_substream *substream)
433{ 438{
434 struct cmi_spec *spec = codec->spec; 439 struct cmi_spec *spec = codec->spec;
435 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 440 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
441 hinfo);
436} 442}
437 443
438static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 444static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index bb915ede0ceb..2bb9a58db9fa 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -98,7 +98,8 @@ static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
98 struct snd_pcm_substream *substream) 98 struct snd_pcm_substream *substream)
99{ 99{
100 struct conexant_spec *spec = codec->spec; 100 struct conexant_spec *spec = codec->spec;
101 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 101 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
102 hinfo);
102} 103}
103 104
104static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 105static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -372,6 +373,11 @@ static int conexant_build_controls(struct hda_codec *codec)
372 spec->multiout.dig_out_nid); 373 spec->multiout.dig_out_nid);
373 if (err < 0) 374 if (err < 0)
374 return err; 375 return err;
376 err = snd_hda_create_spdif_share_sw(codec,
377 &spec->multiout);
378 if (err < 0)
379 return err;
380 spec->multiout.share_spdif = 1;
375 } 381 }
376 if (spec->dig_in_nid) { 382 if (spec->dig_in_nid) {
377 err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); 383 err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d41eafacd86d..6c605813fc6e 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1520,6 +1520,11 @@ static int alc_build_controls(struct hda_codec *codec)
1520 spec->multiout.dig_out_nid); 1520 spec->multiout.dig_out_nid);
1521 if (err < 0) 1521 if (err < 0)
1522 return err; 1522 return err;
1523 err = snd_hda_create_spdif_share_sw(codec,
1524 &spec->multiout);
1525 if (err < 0)
1526 return err;
1527 spec->multiout.share_spdif = 1;
1523 } 1528 }
1524 if (spec->dig_in_nid) { 1529 if (spec->dig_in_nid) {
1525 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 1530 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -2325,7 +2330,8 @@ static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
2325 struct snd_pcm_substream *substream) 2330 struct snd_pcm_substream *substream)
2326{ 2331{
2327 struct alc_spec *spec = codec->spec; 2332 struct alc_spec *spec = codec->spec;
2328 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 2333 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
2334 hinfo);
2329} 2335}
2330 2336
2331static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 2337static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 7f506ef0accb..7901e76f2690 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -916,6 +916,11 @@ static int stac92xx_build_controls(struct hda_codec *codec)
916 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); 916 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
917 if (err < 0) 917 if (err < 0)
918 return err; 918 return err;
919 err = snd_hda_create_spdif_share_sw(codec,
920 &spec->multiout);
921 if (err < 0)
922 return err;
923 spec->multiout.share_spdif = 1;
919 } 924 }
920 if (spec->dig_in_nid) { 925 if (spec->dig_in_nid) {
921 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 926 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -1748,7 +1753,8 @@ static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
1748 struct snd_pcm_substream *substream) 1753 struct snd_pcm_substream *substream)
1749{ 1754{
1750 struct sigmatel_spec *spec = codec->spec; 1755 struct sigmatel_spec *spec = codec->spec;
1751 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 1756 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
1757 hinfo);
1752} 1758}
1753 1759
1754static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 1760static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index d9a5c6a2dd9f..3515a3fb5d9d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -357,7 +357,8 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo,
357 struct snd_pcm_substream *substream) 357 struct snd_pcm_substream *substream)
358{ 358{
359 struct via_spec *spec = codec->spec; 359 struct via_spec *spec = codec->spec;
360 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 360 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
361 hinfo);
361} 362}
362 363
363static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 364static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
@@ -493,6 +494,11 @@ static int via_build_controls(struct hda_codec *codec)
493 spec->multiout.dig_out_nid); 494 spec->multiout.dig_out_nid);
494 if (err < 0) 495 if (err < 0)
495 return err; 496 return err;
497 err = snd_hda_create_spdif_share_sw(codec,
498 &spec->multiout);
499 if (err < 0)
500 return err;
501 spec->multiout.share_spdif = 1;
496 } 502 }
497 if (spec->dig_in_nid) { 503 if (spec->dig_in_nid) {
498 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 504 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);