]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/hda/hda_codec.c
ALSA: hda - Fix caching of SPDIF status bits
[linux-2.6-omap-h63xx.git] / sound / pci / hda / hda_codec.c
index d2e1093f8e972306727255a46ffb7ce7d59ccf2e..eb9164176dab4e3fd0ccb006b77ac5f2eff6dcab 100644 (file)
@@ -64,6 +64,7 @@ static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x14f1, "Conexant" },
        { 0x17e8, "Chrontel" },
        { 0x1854, "LG" },
+       { 0x1aec, "Wolfson Microelectronics" },
        { 0x434d, "C-Media" },
        { 0x8384, "SigmaTel" },
        {} /* terminator */
@@ -93,6 +94,9 @@ static const struct hda_codec_preset *hda_preset_tables[] = {
 #endif
 #ifdef CONFIG_SND_HDA_CODEC_VIA
        snd_hda_preset_via,
+#endif
+#ifdef CONFIG_SND_HDA_CODEC_NVHDMI
+       snd_hda_preset_nvhdmi,
 #endif
        NULL
 };
@@ -211,7 +215,8 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
        unsigned int shift, num_elems, mask;
        hda_nid_t prev_nid;
 
-       snd_assert(conn_list && max_conns > 0, return -EINVAL);
+       if (snd_BUG_ON(!conn_list || max_conns <= 0))
+               return -EINVAL;
 
        parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
@@ -313,7 +318,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
 }
 
 /*
- * process queueud unsolicited events
+ * process queued unsolicited events
  */
 static void process_unsol_events(struct work_struct *work)
 {
@@ -407,8 +412,10 @@ int __devinit snd_hda_bus_new(struct snd_card *card,
                .dev_free = snd_hda_bus_dev_free,
        };
 
-       snd_assert(temp, return -EINVAL);
-       snd_assert(temp->ops.command && temp->ops.get_response, return -EINVAL);
+       if (snd_BUG_ON(!temp))
+               return -EINVAL;
+       if (snd_BUG_ON(!temp->ops.command || !temp->ops.get_response))
+               return -EINVAL;
 
        if (busp)
                *busp = NULL;
@@ -585,11 +592,13 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
                                struct hda_codec **codecp)
 {
        struct hda_codec *codec;
-       char component[13];
+       char component[31];
        int err;
 
-       snd_assert(bus, return -EINVAL);
-       snd_assert(codec_addr <= HDA_MAX_CODEC_ADDRESS, return -EINVAL);
+       if (snd_BUG_ON(!bus))
+               return -EINVAL;
+       if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+               return -EINVAL;
 
        if (bus->caddr_tbl[codec_addr]) {
                snd_printk(KERN_ERR "hda_codec: "
@@ -688,7 +697,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
        snd_hda_create_hwdep(codec);
 #endif
 
-       sprintf(component, "HDA:%08x", codec->vendor_id);
+       sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id);
        snd_component_add(codec->bus->card, component);
 
        if (codecp)
@@ -956,15 +965,6 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
 }
 #endif /* SND_HDA_NEEDS_RESUME */
 
-/*
- * AMP control callbacks
- */
-/* retrieve parameters from private_value */
-#define get_amp_nid(kc)                ((kc)->private_value & 0xffff)
-#define get_amp_channels(kc)   (((kc)->private_value >> 16) & 0x3)
-#define get_amp_direction(kc)  (((kc)->private_value >> 18) & 0x1)
-#define get_amp_index(kc)      (((kc)->private_value >> 19) & 0xf)
-
 /* volume */
 int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_info *uinfo)
@@ -1430,6 +1430,29 @@ static unsigned int convert_to_spdif_status(unsigned short val)
        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_cache(codec, nid, 0, verb, val);
+       d = codec->slave_dig_outs;
+       if (!d)
+               return;
+       for (; *d; d++)
+               snd_hda_codec_write_cache(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(struct snd_kcontrol *kcontrol,
        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(struct snd_kcontrol *kcontrol,
        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))
@@ -2236,11 +2251,13 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
        if (info->ops.close == NULL)
                info->ops.close = hda_pcm_default_open_close;
        if (info->ops.prepare == NULL) {
-               snd_assert(info->nid, return -EINVAL);
+               if (snd_BUG_ON(!info->nid))
+                       return -EINVAL;
                info->ops.prepare = hda_pcm_default_prepare;
        }
        if (info->ops.cleanup == NULL) {
-               snd_assert(info->nid, return -EINVAL);
+               if (snd_BUG_ON(!info->nid))
+                       return -EINVAL;
                info->ops.cleanup = hda_pcm_default_cleanup;
        }
        return 0;
@@ -2583,14 +2600,31 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
                                 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 +2636,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
        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 +2731,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                                             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 +2782,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                                                     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);
@@ -2756,7 +2790,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
 }
 
 /*
- * Helper for automatic ping configuration
+ * Helper for automatic pin configuration
  */
 
 static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list)