diff options
-rw-r--r-- | sound/pci/hda/hda_codec.c | 73 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 13 | ||||
-rw-r--r-- | sound/pci/hda/patch_analog.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_cmedia.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/patch_via.c | 8 |
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 | */ | ||
1538 | static 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 | |||
1546 | static 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 | |||
1554 | static 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 | |||
1562 | int 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 | */ |
2558 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, | 2595 | int 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 | ||
241 | int snd_hda_create_spdif_share_sw(struct hda_codec *codec, | ||
242 | struct hda_multi_out *mout); | ||
233 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, | 243 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, |
234 | struct hda_multi_out *mout); | 244 | struct hda_multi_out *mout); |
235 | int snd_hda_multi_out_dig_close(struct hda_codec *codec, | 245 | int 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); |
242 | int snd_hda_multi_out_analog_open(struct hda_codec *codec, | 252 | int 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); | ||
245 | int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | 256 | int 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 | ||
223 | static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 229 | static 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 | ||
438 | static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 444 | static 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 | ||
104 | static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 105 | static 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 | ||
2331 | static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 2337 | static 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 | ||
1754 | static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 1760 | static 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 | ||
363 | static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 364 | static 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); |