diff options
author | Matthew Ranostay <mranostay@embeddedalley.com> | 2008-09-07 14:31:40 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-09-09 03:11:55 -0400 |
commit | de51ca1267b523d82644b0b752899de693e7190b (patch) | |
tree | 49a7b6e7e9fd95edbc1b5118e3c270db285f2ad3 /sound | |
parent | de30d36be171c05dfd66fa49e3d785e004f5ecdf (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')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 52 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.h | 1 |
2 files changed, 51 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, | |||
2589 | static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, | 2610 | static 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); |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 780e2fffae3a..60468f562400 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -725,6 +725,7 @@ struct hda_codec { | |||
725 | unsigned int spdif_status; /* IEC958 status bits */ | 725 | unsigned int spdif_status; /* IEC958 status bits */ |
726 | unsigned short spdif_ctls; /* SPDIF control bits */ | 726 | unsigned short spdif_ctls; /* SPDIF control bits */ |
727 | unsigned int spdif_in_enable; /* SPDIF input enable? */ | 727 | unsigned int spdif_in_enable; /* SPDIF input enable? */ |
728 | hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ | ||
728 | 729 | ||
729 | struct snd_hwdep *hwdep; /* assigned hwdep device */ | 730 | struct snd_hwdep *hwdep; /* assigned hwdep device */ |
730 | 731 | ||