aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-09-25 10:32:41 -0400
committerJaroslav Kysela <perex@perex.cz>2008-10-10 07:41:34 -0400
commit2f72853ca1ee1571377996471d05db51eb7c54c4 (patch)
tree73b1fd4e56c82a88ad3bea2935e19e0c30830694 /sound/pci
parentddc0f38a62083a552d6acb792d9ce513cf4081df (diff)
ALSA: hda - Fix / clean-up slave digital out codes
The recent slave_dig_out addition has some rooms to clean up. Also it doesn't call snd_hda_cleanup_stream() properly for slaves at closing. The patch fixes both issues. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c115
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 */
1430static 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
1443static 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
1429static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, 1452static 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,
2598static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, 2595static 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) 2616static 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);