]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / alsa-hda-spdif-slave
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave b/src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-spdif-slave
new file mode 100644 (file)
index 0000000..ecfafcf
--- /dev/null
@@ -0,0 +1,334 @@
+From: Takashi Iwai <tiwai@suse.de>
+Subject: ALSA: hda - Slave SPDIF support
+Patch-mainline: 2.6.28-rc1
+References: 
+
+Add the support of slave SPDIF outputs for multiple SPDIF devices.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+
+---
+---
+ sound/pci/hda/hda_codec.c |   72 ++++++++++++++++++++++++++-----------
+ sound/pci/hda/hda_codec.h |   89 +++++++++++++++++++++++++++++++++++++++++++---
+ sound/pci/hda/hda_local.h |   15 ++++---
+ 3 files changed, 146 insertions(+), 30 deletions(-)
+
+--- a/sound/pci/hda/hda_codec.c
++++ b/sound/pci/hda/hda_codec.c
+@@ -1430,6 +1430,29 @@ static unsigned int convert_to_spdif_sta
+       return sbits;
+ }
++/* set digital convert verbs both for the given NID and its slaves */
++static void set_dig_out(struct hda_codec *codec, hda_nid_t nid,
++                      int verb, int val)
++{
++      hda_nid_t *d;
++
++      snd_hda_codec_write(codec, nid, 0, verb, val);
++      d = codec->slave_dig_outs;
++      if (!d)
++              return;
++      for (; *d; d++)
++              snd_hda_codec_write(codec, *d, 0, verb, val);
++}
++
++static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid,
++                                     int dig1, int dig2)
++{
++      if (dig1 != -1)
++              set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1);
++      if (dig2 != -1)
++              set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2);
++}
++
+ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -1448,14 +1471,8 @@ static int snd_hda_spdif_default_put(str
+       change = codec->spdif_ctls != val;
+       codec->spdif_ctls = val;
+-      if (change) {
+-              snd_hda_codec_write_cache(codec, nid, 0,
+-                                        AC_VERB_SET_DIGI_CONVERT_1,
+-                                        val & 0xff);
+-              snd_hda_codec_write_cache(codec, nid, 0,
+-                                        AC_VERB_SET_DIGI_CONVERT_2,
+-                                        val >> 8);
+-      }
++      if (change)
++              set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff);
+       mutex_unlock(&codec->spdif_mutex);
+       return change;
+@@ -1487,9 +1504,7 @@ static int snd_hda_spdif_out_switch_put(
+       change = codec->spdif_ctls != val;
+       if (change) {
+               codec->spdif_ctls = val;
+-              snd_hda_codec_write_cache(codec, nid, 0,
+-                                        AC_VERB_SET_DIGI_CONVERT_1,
+-                                        val & 0xff);
++              set_dig_out_convert(codec, nid, val & 0xff, -1);
+               /* unmute amp switch (if any) */
+               if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) &&
+                   (val & AC_DIG1_ENABLE))
+@@ -2583,14 +2598,31 @@ static void setup_dig_out_stream(struct 
+                                unsigned int stream_tag, unsigned int format)
+ {
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+-      if (codec->spdif_ctls & AC_DIG1_ENABLE)
+-              snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+-                                  codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
++      if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
++              set_dig_out_convert(codec, nid,
++                                  codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff,
++                                  -1);
+       snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
++      if (codec->slave_dig_outs) {
++              hda_nid_t *d;
++              for (d = codec->slave_dig_outs; *d; d++)
++                      snd_hda_codec_setup_stream(codec, *d, stream_tag, 0,
++                                                 format);
++      }
+       /* turn on again (if needed) */
+-      if (codec->spdif_ctls & AC_DIG1_ENABLE)
+-              snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+-                                  codec->spdif_ctls & 0xff);
++      if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE))
++              set_dig_out_convert(codec, nid,
++                                  codec->spdif_ctls & 0xff, -1);
++}
++
++static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)
++{
++      snd_hda_codec_cleanup_stream(codec, nid);
++      if (codec->slave_dig_outs) {
++              hda_nid_t *d;
++              for (d = codec->slave_dig_outs; *d; d++)
++                      snd_hda_codec_cleanup_stream(codec, *d);
++      }
+ }
+ /*
+@@ -2602,7 +2634,7 @@ int snd_hda_multi_out_dig_open(struct hd
+       mutex_lock(&codec->spdif_mutex);
+       if (mout->dig_out_used == HDA_DIG_ANALOG_DUP)
+               /* already opened as analog dup; reset it once */
+-              snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
++              cleanup_dig_out_stream(codec, mout->dig_out_nid);
+       mout->dig_out_used = HDA_DIG_EXCLUSIVE;
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
+@@ -2697,7 +2729,7 @@ int snd_hda_multi_out_analog_prepare(str
+                                            stream_tag, format);
+               } else {
+                       mout->dig_out_used = 0;
+-                      snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
++                      cleanup_dig_out_stream(codec, mout->dig_out_nid);
+               }
+       }
+       mutex_unlock(&codec->spdif_mutex);
+@@ -2748,7 +2780,7 @@ int snd_hda_multi_out_analog_cleanup(str
+                                                    mout->extra_out_nid[i]);
+       mutex_lock(&codec->spdif_mutex);
+       if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
+-              snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid);
++              cleanup_dig_out_stream(codec, mout->dig_out_nid);
+               mout->dig_out_used = 0;
+       }
+       mutex_unlock(&codec->spdif_mutex);
+--- a/sound/pci/hda/hda_codec.h
++++ b/sound/pci/hda/hda_codec.h
+@@ -90,6 +90,14 @@ enum {
+ #define AC_VERB_GET_CONFIG_DEFAULT            0x0f1c
+ /* f20: AFG/MFG */
+ #define AC_VERB_GET_SUBSYSTEM_ID              0x0f20
++#define AC_VERB_GET_CVT_CHAN_COUNT            0x0f2d
++#define AC_VERB_GET_HDMI_DIP_SIZE             0x0f2e
++#define AC_VERB_GET_HDMI_ELDD                 0x0f2f
++#define AC_VERB_GET_HDMI_DIP_INDEX            0x0f30
++#define AC_VERB_GET_HDMI_DIP_DATA             0x0f31
++#define AC_VERB_GET_HDMI_DIP_XMIT             0x0f32
++#define AC_VERB_GET_HDMI_CP_CTRL              0x0f33
++#define AC_VERB_GET_HDMI_CHAN_SLOT            0x0f34
+ /*
+  * SET verbs
+@@ -121,7 +129,14 @@ enum {
+ #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1    0x71d
+ #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2    0x71e
+ #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3    0x71f
++#define AC_VERB_SET_EAPD                              0x788
+ #define AC_VERB_SET_CODEC_RESET                       0x7ff
++#define AC_VERB_SET_CVT_CHAN_COUNT            0x72d
++#define AC_VERB_SET_HDMI_DIP_INDEX            0x730
++#define AC_VERB_SET_HDMI_DIP_DATA             0x731
++#define AC_VERB_SET_HDMI_DIP_XMIT             0x732
++#define AC_VERB_SET_HDMI_CP_CTRL              0x733
++#define AC_VERB_SET_HDMI_CHAN_SLOT            0x734
+ /*
+  * Parameter IDs
+@@ -143,6 +158,7 @@ enum {
+ #define AC_PAR_GPIO_CAP                       0x11
+ #define AC_PAR_AMP_OUT_CAP            0x12
+ #define AC_PAR_VOL_KNB_CAP            0x13
++#define AC_PAR_HDMI_LPCM_CAP          0x20
+ /*
+  * AC_VERB_PARAMETERS results (32bit)
+@@ -171,6 +187,8 @@ enum {
+ #define AC_WCAP_DIGITAL                       (1<<9)  /* digital I/O */
+ #define AC_WCAP_POWER                 (1<<10) /* power control */
+ #define AC_WCAP_LR_SWAP                       (1<<11) /* L/R swap */
++#define AC_WCAP_CP_CAPS                       (1<<12) /* content protection */
++#define AC_WCAP_CHAN_CNT_EXT          (7<<13) /* channel count ext */
+ #define AC_WCAP_DELAY                 (0xf<<16)
+ #define AC_WCAP_DELAY_SHIFT           16
+ #define AC_WCAP_TYPE                  (0xf<<20)
+@@ -206,9 +224,20 @@ enum {
+ /* Input converter SDI select */
+ #define AC_SDI_SELECT                 (0xf<<0)
+-/* Unsolicited response */
++/* Unsolicited response control */
+ #define AC_UNSOL_TAG                  (0x3f<<0)
+ #define AC_UNSOL_ENABLED              (1<<7)
++#define AC_USRSP_EN                   AC_UNSOL_ENABLED
++
++/* Unsolicited responses */
++#define AC_UNSOL_RES_TAG              (0x3f<<26)
++#define AC_UNSOL_RES_TAG_SHIFT                26
++#define AC_UNSOL_RES_SUBTAG           (0x1f<<21)
++#define AC_UNSOL_RES_SUBTAG_SHIFT     21
++#define AC_UNSOL_RES_ELDV             (1<<1)  /* ELD Data valid (for HDMI) */
++#define AC_UNSOL_RES_PD                       (1<<0)  /* pinsense detect */
++#define AC_UNSOL_RES_CP_STATE         (1<<1)  /* content protection */
++#define AC_UNSOL_RES_CP_READY         (1<<0)  /* content protection */
+ /* Pin widget capabilies */
+ #define AC_PINCAP_IMP_SENSE           (1<<0)  /* impedance sense capable */
+@@ -222,6 +251,10 @@ enum {
+  *       but is marked reserved in the Intel HDA specification.
+  */
+ #define AC_PINCAP_LR_SWAP             (1<<7)  /* L/R swap */
++/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
++ *       in HD-audio specification
++ */
++#define AC_PINCAP_HDMI                        (1<<7)  /* HDMI pin */
+ #define AC_PINCAP_VREF                        (0x37<<8)
+ #define AC_PINCAP_VREF_SHIFT          8
+ #define AC_PINCAP_EAPD                        (1<<16) /* EAPD capable */
+@@ -272,6 +305,22 @@ enum {
+ #define AC_KNBCAP_NUM_STEPS           (0x7f<<0)
+ #define AC_KNBCAP_DELTA                       (1<<7)
++/* HDMI LPCM capabilities */
++#define AC_LPCMCAP_48K_CP_CHNS                (0x0f<<0) /* max channels w/ CP-on */
++#define AC_LPCMCAP_48K_NO_CHNS                (0x0f<<4) /* max channels w/o CP-on */
++#define AC_LPCMCAP_48K_20BIT          (1<<8)  /* 20b bitrate supported */
++#define AC_LPCMCAP_48K_24BIT          (1<<9)  /* 24b bitrate supported */
++#define AC_LPCMCAP_96K_CP_CHNS                (0x0f<<10) /* max channels w/ CP-on */
++#define AC_LPCMCAP_96K_NO_CHNS                (0x0f<<14) /* max channels w/o CP-on */
++#define AC_LPCMCAP_96K_20BIT          (1<<18) /* 20b bitrate supported */
++#define AC_LPCMCAP_96K_24BIT          (1<<19) /* 24b bitrate supported */
++#define AC_LPCMCAP_192K_CP_CHNS               (0x0f<<20) /* max channels w/ CP-on */
++#define AC_LPCMCAP_192K_NO_CHNS               (0x0f<<24) /* max channels w/o CP-on */
++#define AC_LPCMCAP_192K_20BIT         (1<<28) /* 20b bitrate supported */
++#define AC_LPCMCAP_192K_24BIT         (1<<29) /* 24b bitrate supported */
++#define AC_LPCMCAP_44K                        (1<<30) /* 44.1kHz support */
++#define AC_LPCMCAP_44K_MS             (1<<31) /* 44.1kHz-multiplies support */
++
+ /*
+  * Control Parameters
+  */
+@@ -317,18 +366,44 @@ enum {
+ #define AC_PINCTL_OUT_EN              (1<<6)
+ #define AC_PINCTL_HP_EN                       (1<<7)
+-/* Unsolicited response - 8bit */
+-#define AC_USRSP_EN                   (1<<7)
+-
+ /* Pin sense - 32bit */
+ #define AC_PINSENSE_IMPEDANCE_MASK    (0x7fffffff)
+ #define AC_PINSENSE_PRESENCE          (1<<31)
++#define AC_PINSENSE_ELDV              (1<<30) /* ELD valid (HDMI) */
+ /* EAPD/BTL enable - 32bit */
+ #define AC_EAPDBTL_BALANCED           (1<<0)
+ #define AC_EAPDBTL_EAPD                       (1<<1)
+ #define AC_EAPDBTL_LR_SWAP            (1<<2)
++/* HDMI ELD data */
++#define AC_ELDD_ELD_VALID             (1<<31)
++#define AC_ELDD_ELD_DATA              0xff
++
++/* HDMI DIP size */
++#define AC_DIPSIZE_ELD_BUF            (1<<3) /* ELD buf size of packet size */
++#define AC_DIPSIZE_PACK_IDX           (0x07<<0) /* packet index */
++
++/* HDMI DIP index */
++#define AC_DIPIDX_PACK_IDX            (0x07<<5) /* packet idnex */
++#define AC_DIPIDX_BYTE_IDX            (0x1f<<0) /* byte index */
++
++/* HDMI DIP xmit (transmit) control */
++#define AC_DIPXMIT_MASK                       (0x3<<6)
++#define AC_DIPXMIT_DISABLE            (0x0<<6) /* disable xmit */
++#define AC_DIPXMIT_ONCE                       (0x2<<6) /* xmit once then disable */
++#define AC_DIPXMIT_BEST                       (0x3<<6) /* best effort */
++
++/* HDMI content protection (CP) control */
++#define AC_CPCTRL_CES                 (1<<9) /* current encryption state */
++#define AC_CPCTRL_READY                       (1<<8) /* ready bit */
++#define AC_CPCTRL_SUBTAG              (0x1f<<3) /* subtag for unsol-resp */
++#define AC_CPCTRL_STATE                       (3<<0) /* current CP request state */
++
++/* Converter channel <-> HDMI slot mapping */
++#define AC_CVTMAP_HDMI_SLOT           (0xf<<0) /* HDMI slot number */
++#define AC_CVTMAP_CHAN                        (0xf<<4) /* converter channel number */
++
+ /* configuration default - 32bit */
+ #define AC_DEFCFG_SEQUENCE            (0xf<<0)
+ #define AC_DEFCFG_DEF_ASSOC           (0xf<<4)
+@@ -650,9 +725,15 @@ struct hda_codec {
+       unsigned int spdif_status;      /* IEC958 status bits */
+       unsigned short spdif_ctls;      /* SPDIF control bits */
+       unsigned int spdif_in_enable;   /* SPDIF input enable? */
++      hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
+       struct snd_hwdep *hwdep;        /* assigned hwdep device */
++      /* misc flags */
++      unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each
++                                           * status change
++                                           * (e.g. Realtek codecs)
++                                           */
+ #ifdef CONFIG_SND_HDA_POWER_SAVE
+       unsigned int power_on :1;       /* current (global) power-state */
+       unsigned int power_transition :1; /* power-state in transition */
+--- a/sound/pci/hda/hda_local.h
++++ b/sound/pci/hda/hda_local.h
+@@ -368,12 +368,15 @@ int snd_hda_parse_pin_def_config(struct 
+ #define AMP_OUT_UNMUTE        0xb000
+ #define AMP_OUT_ZERO  0xb000
+ /* pinctl values */
+-#define PIN_IN                0x20
+-#define PIN_VREF80    0x24
+-#define PIN_VREF50    0x21
+-#define PIN_OUT               0x40
+-#define PIN_HP                0xc0
+-#define PIN_HP_AMP    0x80
++#define PIN_IN                        (AC_PINCTL_IN_EN)
++#define PIN_VREFHIZ   (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ)
++#define PIN_VREF50            (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50)
++#define PIN_VREFGRD   (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD)
++#define PIN_VREF80            (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80)
++#define PIN_VREF100   (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100)
++#define PIN_OUT               (AC_PINCTL_OUT_EN)
++#define PIN_HP                        (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
++#define PIN_HP_AMP            (AC_PINCTL_HP_EN)
+ /*
+  * get widget capabilities