diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 115 |
1 files changed, 50 insertions, 65 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index cb9aae5e9ca5..94ea6543440e 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1426,6 +1426,29 @@ static unsigned int convert_to_spdif_status(unsigned short val) | |||
1426 | return sbits; | 1426 | return sbits; |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | /* set digital convert verbs both for the given NID and its slaves */ | ||
1430 | static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, | ||
1431 | int verb, int val) | ||
1432 | { | ||
1433 | hda_nid_t *d; | ||
1434 | |||
1435 | snd_hda_codec_write(codec, nid, 0, verb, val); | ||
1436 | d = codec->slave_dig_outs; | ||
1437 | if (!d) | ||
1438 | return; | ||
1439 | for (; *d; d++) | ||
1440 | snd_hda_codec_write(codec, *d, 0, verb, val); | ||
1441 | } | ||
1442 | |||
1443 | static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, | ||
1444 | int dig1, int dig2) | ||
1445 | { | ||
1446 | if (dig1 != -1) | ||
1447 | set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1); | ||
1448 | if (dig2 != -1) | ||
1449 | set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2); | ||
1450 | } | ||
1451 | |||
1429 | static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, | 1452 | static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, |
1430 | struct snd_ctl_elem_value *ucontrol) | 1453 | struct snd_ctl_elem_value *ucontrol) |
1431 | { | 1454 | { |
@@ -1444,25 +1467,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
1444 | change = codec->spdif_ctls != val; | 1467 | change = codec->spdif_ctls != val; |
1445 | codec->spdif_ctls = val; | 1468 | codec->spdif_ctls = val; |
1446 | 1469 | ||
1447 | if (change) { | 1470 | if (change) |
1448 | hda_nid_t *d; | 1471 | set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); |
1449 | snd_hda_codec_write_cache(codec, nid, 0, | ||
1450 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1451 | val & 0xff); | ||
1452 | snd_hda_codec_write_cache(codec, nid, 0, | ||
1453 | AC_VERB_SET_DIGI_CONVERT_2, | ||
1454 | val >> 8); | ||
1455 | |||
1456 | if (codec->slave_dig_outs) | ||
1457 | for (d = codec->slave_dig_outs; *d; d++) { | ||
1458 | snd_hda_codec_write_cache(codec, *d, 0, | ||
1459 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1460 | val & 0xff); | ||
1461 | snd_hda_codec_write_cache(codec, *d, 0, | ||
1462 | AC_VERB_SET_DIGI_CONVERT_2, | ||
1463 | val >> 8); | ||
1464 | } | ||
1465 | } | ||
1466 | 1472 | ||
1467 | mutex_unlock(&codec->spdif_mutex); | 1473 | mutex_unlock(&codec->spdif_mutex); |
1468 | return change; | 1474 | return change; |
@@ -1493,17 +1499,8 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, | |||
1493 | val |= AC_DIG1_ENABLE; | 1499 | val |= AC_DIG1_ENABLE; |
1494 | change = codec->spdif_ctls != val; | 1500 | change = codec->spdif_ctls != val; |
1495 | if (change) { | 1501 | if (change) { |
1496 | hda_nid_t *d; | ||
1497 | codec->spdif_ctls = val; | 1502 | codec->spdif_ctls = val; |
1498 | snd_hda_codec_write_cache(codec, nid, 0, | 1503 | set_dig_out_convert(codec, nid, val & 0xff, -1); |
1499 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1500 | val & 0xff); | ||
1501 | |||
1502 | if (codec->slave_dig_outs) | ||
1503 | for (d = codec->slave_dig_outs; *d; d++) | ||
1504 | snd_hda_codec_write_cache(codec, *d, 0, | ||
1505 | AC_VERB_SET_DIGI_CONVERT_1, | ||
1506 | val & 0xff); | ||
1507 | /* unmute amp switch (if any) */ | 1504 | /* unmute amp switch (if any) */ |
1508 | if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && | 1505 | if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && |
1509 | (val & AC_DIG1_ENABLE)) | 1506 | (val & AC_DIG1_ENABLE)) |
@@ -2598,32 +2595,32 @@ int snd_hda_input_mux_put(struct hda_codec *codec, | |||
2598 | static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, | 2595 | static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, |
2599 | unsigned int stream_tag, unsigned int format) | 2596 | unsigned int stream_tag, unsigned int format) |
2600 | { | 2597 | { |
2601 | hda_nid_t *d; | ||
2602 | |||
2603 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | 2598 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ |
2604 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { | 2599 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) |
2605 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 2600 | set_dig_out_convert(codec, nid, |
2606 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | 2601 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, |
2607 | 2602 | -1); | |
2608 | if (codec->slave_dig_outs) | ||
2609 | for (d = codec->slave_dig_outs; *d; d++) | ||
2610 | snd_hda_codec_write(codec, *d, 0, | ||
2611 | AC_VERB_SET_DIGI_CONVERT_1, | ||
2612 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | ||
2613 | } | ||
2614 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); | 2603 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); |
2604 | if (codec->slave_dig_outs) { | ||
2605 | hda_nid_t *d; | ||
2606 | for (d = codec->slave_dig_outs; *d; d++) | ||
2607 | snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, | ||
2608 | format); | ||
2609 | } | ||
2615 | /* turn on again (if needed) */ | 2610 | /* turn on again (if needed) */ |
2616 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { | 2611 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) |
2617 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | 2612 | set_dig_out_convert(codec, nid, |
2618 | codec->spdif_ctls & 0xff); | 2613 | codec->spdif_ctls & 0xff, -1); |
2614 | } | ||
2619 | 2615 | ||
2620 | if (codec->slave_dig_outs) | 2616 | static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) |
2621 | for (d = codec->slave_dig_outs; *d; d++) | 2617 | { |
2622 | snd_hda_codec_write(codec, *d, 0, | 2618 | snd_hda_codec_cleanup_stream(codec, nid); |
2623 | AC_VERB_SET_DIGI_CONVERT_1, | 2619 | if (codec->slave_dig_outs) { |
2624 | codec->spdif_ctls & 0xff); | 2620 | hda_nid_t *d; |
2621 | for (d = codec->slave_dig_outs; *d; d++) | ||
2622 | snd_hda_codec_cleanup_stream(codec, *d); | ||
2625 | } | 2623 | } |
2626 | |||
2627 | } | 2624 | } |
2628 | 2625 | ||
2629 | /* | 2626 | /* |
@@ -2635,7 +2632,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, | |||
2635 | mutex_lock(&codec->spdif_mutex); | 2632 | mutex_lock(&codec->spdif_mutex); |
2636 | if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) | 2633 | if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) |
2637 | /* already opened as analog dup; reset it once */ | 2634 | /* already opened as analog dup; reset it once */ |
2638 | snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | 2635 | cleanup_dig_out_stream(codec, mout->dig_out_nid); |
2639 | mout->dig_out_used = HDA_DIG_EXCLUSIVE; | 2636 | mout->dig_out_used = HDA_DIG_EXCLUSIVE; |
2640 | mutex_unlock(&codec->spdif_mutex); | 2637 | mutex_unlock(&codec->spdif_mutex); |
2641 | return 0; | 2638 | return 0; |
@@ -2647,12 +2644,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, | |||
2647 | unsigned int format, | 2644 | unsigned int format, |
2648 | struct snd_pcm_substream *substream) | 2645 | struct snd_pcm_substream *substream) |
2649 | { | 2646 | { |
2650 | hda_nid_t *nid; | ||
2651 | mutex_lock(&codec->spdif_mutex); | 2647 | mutex_lock(&codec->spdif_mutex); |
2652 | setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); | 2648 | setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); |
2653 | if (codec->slave_dig_outs) | ||
2654 | for (nid = codec->slave_dig_outs; *nid; nid++) | ||
2655 | setup_dig_out_stream(codec, *nid, stream_tag, format); | ||
2656 | mutex_unlock(&codec->spdif_mutex); | 2649 | mutex_unlock(&codec->spdif_mutex); |
2657 | return 0; | 2650 | return 0; |
2658 | } | 2651 | } |
@@ -2719,7 +2712,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | |||
2719 | struct snd_pcm_substream *substream) | 2712 | struct snd_pcm_substream *substream) |
2720 | { | 2713 | { |
2721 | hda_nid_t *nids = mout->dac_nids; | 2714 | hda_nid_t *nids = mout->dac_nids; |
2722 | hda_nid_t *d; | ||
2723 | int chs = substream->runtime->channels; | 2715 | int chs = substream->runtime->channels; |
2724 | int i; | 2716 | int i; |
2725 | 2717 | ||
@@ -2733,16 +2725,9 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | |||
2733 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; | 2725 | mout->dig_out_used = HDA_DIG_ANALOG_DUP; |
2734 | setup_dig_out_stream(codec, mout->dig_out_nid, | 2726 | setup_dig_out_stream(codec, mout->dig_out_nid, |
2735 | stream_tag, format); | 2727 | stream_tag, format); |
2736 | if (codec->slave_dig_outs) | ||
2737 | for (d = codec->slave_dig_outs; *d; d++) | ||
2738 | setup_dig_out_stream(codec, *d, | ||
2739 | stream_tag, format); | ||
2740 | } else { | 2728 | } else { |
2741 | mout->dig_out_used = 0; | 2729 | mout->dig_out_used = 0; |
2742 | snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | 2730 | cleanup_dig_out_stream(codec, mout->dig_out_nid); |
2743 | if (codec->slave_dig_outs) | ||
2744 | for (d = codec->slave_dig_outs; *d; d++) | ||
2745 | snd_hda_codec_cleanup_stream(codec, *d); | ||
2746 | } | 2731 | } |
2747 | } | 2732 | } |
2748 | mutex_unlock(&codec->spdif_mutex); | 2733 | mutex_unlock(&codec->spdif_mutex); |
@@ -2793,7 +2778,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, | |||
2793 | mout->extra_out_nid[i]); | 2778 | mout->extra_out_nid[i]); |
2794 | mutex_lock(&codec->spdif_mutex); | 2779 | mutex_lock(&codec->spdif_mutex); |
2795 | if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | 2780 | if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { |
2796 | snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | 2781 | cleanup_dig_out_stream(codec, mout->dig_out_nid); |
2797 | mout->dig_out_used = 0; | 2782 | mout->dig_out_used = 0; |
2798 | } | 2783 | } |
2799 | mutex_unlock(&codec->spdif_mutex); | 2784 | mutex_unlock(&codec->spdif_mutex); |