aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
authorMatthew Ranostay <mranostay@embeddedalley.com>2008-09-07 14:31:40 -0400
committerJaroslav Kysela <perex@perex.cz>2008-09-09 03:11:55 -0400
commitde51ca1267b523d82644b0b752899de693e7190b (patch)
tree49a7b6e7e9fd95edbc1b5118e3c270db285f2ad3 /sound/pci/hda/hda_codec.c
parentde30d36be171c05dfd66fa49e3d785e004f5ecdf (diff)
ALSA: hda: slave digital out support
Added support for playing a stream on multiple digital outs. This is done by defining codec->slave_dig_outs as array of hda_nid_t with a null-terminated entry to set the slave SPDIF outs, in which the slave outs have cloned settings of the master out (e.g. dig_out_nid). Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c52
1 files changed, 50 insertions, 2 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 4f3291150809..696d77e575ec 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1454,12 +1454,22 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
1454 codec->spdif_ctls = val; 1454 codec->spdif_ctls = val;
1455 1455
1456 if (change) { 1456 if (change) {
1457 hda_nid_t *d;
1457 snd_hda_codec_write_cache(codec, nid, 0, 1458 snd_hda_codec_write_cache(codec, nid, 0,
1458 AC_VERB_SET_DIGI_CONVERT_1, 1459 AC_VERB_SET_DIGI_CONVERT_1,
1459 val & 0xff); 1460 val & 0xff);
1460 snd_hda_codec_write_cache(codec, nid, 0, 1461 snd_hda_codec_write_cache(codec, nid, 0,
1461 AC_VERB_SET_DIGI_CONVERT_2, 1462 AC_VERB_SET_DIGI_CONVERT_2,
1462 val >> 8); 1463 val >> 8);
1464
1465 for (d = codec->slave_dig_outs; *d; d++) {
1466 snd_hda_codec_write_cache(codec, *d, 0,
1467 AC_VERB_SET_DIGI_CONVERT_1,
1468 val & 0xff);
1469 snd_hda_codec_write_cache(codec, *d, 0,
1470 AC_VERB_SET_DIGI_CONVERT_2,
1471 val >> 8);
1472 }
1463 } 1473 }
1464 1474
1465 mutex_unlock(&codec->spdif_mutex); 1475 mutex_unlock(&codec->spdif_mutex);
@@ -1491,10 +1501,16 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
1491 val |= AC_DIG1_ENABLE; 1501 val |= AC_DIG1_ENABLE;
1492 change = codec->spdif_ctls != val; 1502 change = codec->spdif_ctls != val;
1493 if (change) { 1503 if (change) {
1504 hda_nid_t *d;
1494 codec->spdif_ctls = val; 1505 codec->spdif_ctls = val;
1495 snd_hda_codec_write_cache(codec, nid, 0, 1506 snd_hda_codec_write_cache(codec, nid, 0,
1496 AC_VERB_SET_DIGI_CONVERT_1, 1507 AC_VERB_SET_DIGI_CONVERT_1,
1497 val & 0xff); 1508 val & 0xff);
1509
1510 for (d = codec->slave_dig_outs; *d; d++)
1511 snd_hda_codec_write_cache(codec, *d, 0,
1512 AC_VERB_SET_DIGI_CONVERT_1,
1513 val & 0xff);
1498 /* unmute amp switch (if any) */ 1514 /* unmute amp switch (if any) */
1499 if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && 1515 if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
1500 (val & AC_DIG1_ENABLE)) 1516 (val & AC_DIG1_ENABLE))
@@ -1643,9 +1659,14 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,
1643 mutex_lock(&codec->spdif_mutex); 1659 mutex_lock(&codec->spdif_mutex);
1644 change = codec->spdif_in_enable != val; 1660 change = codec->spdif_in_enable != val;
1645 if (change) { 1661 if (change) {
1662 hda_nid_t *d;
1646 codec->spdif_in_enable = val; 1663 codec->spdif_in_enable = val;
1647 snd_hda_codec_write_cache(codec, nid, 0, 1664 snd_hda_codec_write_cache(codec, nid, 0,
1648 AC_VERB_SET_DIGI_CONVERT_1, val); 1665 AC_VERB_SET_DIGI_CONVERT_1, val);
1666
1667 for (d = codec->slave_dig_outs; *d; d++)
1668 snd_hda_codec_write_cache(codec, *d, 0,
1669 AC_VERB_SET_DIGI_CONVERT_1, val);
1649 } 1670 }
1650 mutex_unlock(&codec->spdif_mutex); 1671 mutex_unlock(&codec->spdif_mutex);
1651 return change; 1672 return change;
@@ -2589,15 +2610,30 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
2589static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, 2610static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
2590 unsigned int stream_tag, unsigned int format) 2611 unsigned int stream_tag, unsigned int format)
2591{ 2612{
2613 hda_nid_t *d;
2614
2592 /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ 2615 /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
2593 if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) 2616 if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
2594 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 2617 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
2618 codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
2619
2620 for (d = codec->slave_dig_outs; *d; d++)
2621 snd_hda_codec_write(codec, *d, 0,
2622 AC_VERB_SET_DIGI_CONVERT_1,
2595 codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); 2623 codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
2624 }
2596 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); 2625 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
2597 /* turn on again (if needed) */ 2626 /* turn on again (if needed) */
2598 if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) 2627 if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) {
2599 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 2628 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
2600 codec->spdif_ctls & 0xff); 2629 codec->spdif_ctls & 0xff);
2630
2631 for (d = codec->slave_dig_outs; *d; d++)
2632 snd_hda_codec_write(codec, *d, 0,
2633 AC_VERB_SET_DIGI_CONVERT_1,
2634 codec->spdif_ctls & 0xff);
2635 }
2636
2601} 2637}
2602 2638
2603/* 2639/*
@@ -2621,8 +2657,12 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
2621 unsigned int format, 2657 unsigned int format,
2622 struct snd_pcm_substream *substream) 2658 struct snd_pcm_substream *substream)
2623{ 2659{
2660 hda_nid_t *nid;
2624 mutex_lock(&codec->spdif_mutex); 2661 mutex_lock(&codec->spdif_mutex);
2625 setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format); 2662 setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
2663 if (codec->slave_dig_outs)
2664 for (nid = codec->slave_dig_outs; *nid; nid++)
2665 setup_dig_out_stream(codec, *nid, stream_tag, format);
2626 mutex_unlock(&codec->spdif_mutex); 2666 mutex_unlock(&codec->spdif_mutex);
2627 return 0; 2667 return 0;
2628} 2668}
@@ -2689,6 +2729,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
2689 struct snd_pcm_substream *substream) 2729 struct snd_pcm_substream *substream)
2690{ 2730{
2691 hda_nid_t *nids = mout->dac_nids; 2731 hda_nid_t *nids = mout->dac_nids;
2732 hda_nid_t *d;
2692 int chs = substream->runtime->channels; 2733 int chs = substream->runtime->channels;
2693 int i; 2734 int i;
2694 2735
@@ -2702,9 +2743,16 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
2702 mout->dig_out_used = HDA_DIG_ANALOG_DUP; 2743 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
2703 setup_dig_out_stream(codec, mout->dig_out_nid, 2744 setup_dig_out_stream(codec, mout->dig_out_nid,
2704 stream_tag, format); 2745 stream_tag, format);
2746 if (codec->slave_dig_outs)
2747 for (d = codec->slave_dig_outs; *d; d++)
2748 setup_dig_out_stream(codec, *d,
2749 stream_tag, format);
2705 } else { 2750 } else {
2706 mout->dig_out_used = 0; 2751 mout->dig_out_used = 0;
2707 snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); 2752 snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
2753 if (codec->slave_dig_outs)
2754 for (d = codec->slave_dig_outs; *d; d++)
2755 snd_hda_codec_cleanup_stream(codec, *d);
2708 } 2756 }
2709 } 2757 }
2710 mutex_unlock(&codec->spdif_mutex); 2758 mutex_unlock(&codec->spdif_mutex);