ALSA: hda - Check subdevice mask in snd_hda_check_board_codec_sid_config()
[pandora-kernel.git] / sound / pci / hda / hda_codec.c
index f3aefef..4562e9d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/mutex.h>
+#include <linux/module.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include <sound/asoundef.h>
@@ -34,6 +35,9 @@
 #include "hda_beep.h"
 #include <sound/hda_hwdep.h>
 
+#define CREATE_TRACE_POINTS
+#include "hda_trace.h"
+
 /*
  * vendor / preset table
  */
@@ -208,15 +212,19 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
  again:
        snd_hda_power_up(codec);
        mutex_lock(&bus->cmd_mutex);
+       trace_hda_send_cmd(codec, cmd);
        err = bus->ops.command(bus, cmd);
-       if (!err && res)
+       if (!err && res) {
                *res = bus->ops.get_response(bus, codec->addr);
+               trace_hda_get_response(codec, *res);
+       }
        mutex_unlock(&bus->cmd_mutex);
        snd_hda_power_down(codec);
        if (res && *res == -1 && bus->rirb_error) {
                if (bus->response_reset) {
                        snd_printd("hda_codec: resetting BUS due to "
                                   "fatal communication error\n");
+                       trace_hda_bus_reset(bus);
                        bus->ops.bus_reset(bus);
                }
                goto again;
@@ -607,6 +615,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
        struct hda_bus_unsolicited *unsol;
        unsigned int wp;
 
+       trace_hda_unsol_event(bus, res, res_ex);
        unsol = bus->unsol;
        if (!unsol)
                return 0;
@@ -1483,8 +1492,11 @@ static void really_cleanup_stream(struct hda_codec *codec,
                                  struct hda_cvt_setup *q)
 {
        hda_nid_t nid = q->nid;
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+       if (q->stream_tag || q->channel_id)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       if (q->format_id)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0
+);
        memset(q, 0, sizeof(*q));
        q->nid = nid;
 }
@@ -1688,6 +1700,29 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
 }
 EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
 
+/**
+ * snd_hda_override_pin_caps - Override the pin capabilities
+ * @codec: the CODEC
+ * @nid: the NID to override
+ * @caps: the capability bits to set
+ *
+ * Override the cached PIN capabilitiy bits value by the given one.
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
+                             unsigned int caps)
+{
+       struct hda_amp_info *info;
+       info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
+       if (!info)
+               return -ENOMEM;
+       info->amp_caps = caps;
+       info->head.val |= INFO_AMP_CAPS;
+       return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
+
 /**
  * snd_hda_pin_sense - execute pin sense measurement
  * @codec: the CODEC to sense
@@ -2296,6 +2331,39 @@ int snd_hda_codec_reset(struct hda_codec *codec)
        return 0;
 }
 
+typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *);
+
+/* apply the function to all matching slave ctls in the mixer list */
+static int map_slaves(struct hda_codec *codec, const char * const *slaves,
+                     map_slave_func_t func, void *data) 
+{
+       struct hda_nid_item *items;
+       const char * const *s;
+       int i, err;
+
+       items = codec->mixers.list;
+       for (i = 0; i < codec->mixers.used; i++) {
+               struct snd_kcontrol *sctl = items[i].kctl;
+               if (!sctl || !sctl->id.name ||
+                   sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
+                       continue;
+               for (s = slaves; *s; s++) {
+                       if (!strcmp(sctl->id.name, *s)) {
+                               err = func(data, sctl);
+                               if (err)
+                                       return err;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int check_slave_present(void *data, struct snd_kcontrol *sctl)
+{
+       return 1;
+}
+
 /**
  * snd_hda_add_vmaster - create a virtual master control and add slaves
  * @codec: HD-audio codec
@@ -2316,12 +2384,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
                        unsigned int *tlv, const char * const *slaves)
 {
        struct snd_kcontrol *kctl;
-       const char * const *s;
        int err;
 
-       for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++)
-               ;
-       if (!*s) {
+       err = map_slaves(codec, slaves, check_slave_present, NULL);
+       if (err != 1) {
                snd_printdd("No slave found for %s\n", name);
                return 0;
        }
@@ -2332,23 +2398,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
        if (err < 0)
                return err;
 
-       for (s = slaves; *s; s++) {
-               struct snd_kcontrol *sctl;
-               int i = 0;
-               for (;;) {
-                       sctl = _snd_hda_find_mixer_ctl(codec, *s, i);
-                       if (!sctl) {
-                               if (!i)
-                                       snd_printdd("Cannot find slave %s, "
-                                                   "skipped\n", *s);
-                               break;
-                       }
-                       err = snd_ctl_add_slave(kctl, sctl);
-                       if (err < 0)
-                               return err;
-                       i++;
-               }
-       }
+       err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave,
+                        kctl);
+       if (err < 0)
+               return err;
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_add_vmaster);
@@ -3993,9 +4046,9 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
 
        /* Search for codec ID */
        for (q = tbl; q->subvendor; q++) {
-               unsigned long vendorid = (q->subdevice) | (q->subvendor << 16);
-
-               if (vendorid == codec->subsystem_id)
+               unsigned int mask = 0xffff0000 | q->subdevice_mask;
+               unsigned int id = (q->subdevice | (q->subvendor << 16)) & mask;
+               if ((codec->subsystem_id & mask) == id)
                        break;
        }
 
@@ -4087,6 +4140,7 @@ static void hda_power_work(struct work_struct *work)
                return;
        }
 
+       trace_hda_power_down(codec);
        hda_call_codec_suspend(codec);
        if (bus->ops.pm_notify)
                bus->ops.pm_notify(bus);
@@ -4125,6 +4179,7 @@ void snd_hda_power_up(struct hda_codec *codec)
        if (codec->power_on || codec->power_transition)
                return;
 
+       trace_hda_power_up(codec);
        snd_hda_update_power_acct(codec);
        codec->power_on = 1;
        codec->power_jiffies = jiffies;
@@ -4537,6 +4592,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
                snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag,
                                           0, format);
        /* extra outputs copied from front */
+       for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
+               if (!mout->no_share_stream && mout->hp_out_nid[i])
+                       snd_hda_codec_setup_stream(codec,
+                                                  mout->hp_out_nid[i],
+                                                  stream_tag, 0, format);
        for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
                if (!mout->no_share_stream && mout->extra_out_nid[i])
                        snd_hda_codec_setup_stream(codec,
@@ -4569,6 +4629,10 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
                snd_hda_codec_cleanup_stream(codec, nids[i]);
        if (mout->hp_nid)
                snd_hda_codec_cleanup_stream(codec, mout->hp_nid);
+       for (i = 0; i < ARRAY_SIZE(mout->hp_out_nid); i++)
+               if (mout->hp_out_nid[i])
+                       snd_hda_codec_cleanup_stream(codec,
+                                                    mout->hp_out_nid[i]);
        for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
                if (mout->extra_out_nid[i])
                        snd_hda_codec_cleanup_stream(codec,
@@ -4649,6 +4713,27 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
        }
 }
 
+/* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ *    4-ch: front/surr  =>  OK as it is
+ *    6-ch: front/clfe/surr
+ *    8-ch: front/clfe/rear/side|fc
+ */
+static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
+{
+       hda_nid_t nid;
+
+       switch (nums) {
+       case 3:
+       case 4:
+               nid = pins[1];
+               pins[1] = pins[2];
+               pins[2] = nid;
+               break;
+       }
+}
+
 /*
  * Parse all pin widgets and store the useful pin nids to cfg
  *
@@ -4666,12 +4751,13 @@ static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
  * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
  * respectively.
  */
-int snd_hda_parse_pin_def_config(struct hda_codec *codec,
-                                struct auto_pin_cfg *cfg,
-                                const hda_nid_t *ignore_nids)
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+                            struct auto_pin_cfg *cfg,
+                            const hda_nid_t *ignore_nids,
+                            unsigned int cond_flags)
 {
        hda_nid_t nid, end_nid;
-       short seq, assoc_line_out, assoc_speaker;
+       short seq, assoc_line_out;
        short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
        short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
        short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
@@ -4682,8 +4768,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        memset(sequences_line_out, 0, sizeof(sequences_line_out));
        memset(sequences_speaker, 0, sizeof(sequences_speaker));
        memset(sequences_hp, 0, sizeof(sequences_hp));
-       assoc_line_out = assoc_speaker = 0;
+       assoc_line_out = 0;
 
+       codec->ignore_misc_bit = true;
        end_nid = codec->start_nid + codec->num_nodes;
        for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
@@ -4699,6 +4786,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                        continue;
 
                def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+                     AC_DEFCFG_MISC_NO_PRESENCE))
+                       codec->ignore_misc_bit = false;
                conn = get_defcfg_connect(def_conf);
                if (conn == AC_JACK_PORT_NONE)
                        continue;
@@ -4734,16 +4824,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                case AC_JACK_SPEAKER:
                        seq = get_defcfg_sequence(def_conf);
                        assoc = get_defcfg_association(def_conf);
-                       if (!assoc)
-                               continue;
-                       if (!assoc_speaker)
-                               assoc_speaker = assoc;
-                       else if (assoc_speaker != assoc)
-                               continue;
                        if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
                                continue;
                        cfg->speaker_pins[cfg->speaker_outs] = nid;
-                       sequences_speaker[cfg->speaker_outs] = seq;
+                       sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
                        cfg->speaker_outs++;
                        break;
                case AC_JACK_HP_OUT:
@@ -4792,7 +4876,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
         * If no line-out is defined but multiple HPs are found,
         * some of them might be the real line-outs.
         */
-       if (!cfg->line_outs && cfg->hp_outs > 1) {
+       if (!cfg->line_outs && cfg->hp_outs > 1 &&
+           !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
                int i = 0;
                while (i < cfg->hp_outs) {
                        /* The real HPs should have the sequence 0x0f */
@@ -4829,7 +4914,8 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
         * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
         * as a primary output
         */
-       if (!cfg->line_outs) {
+       if (!cfg->line_outs &&
+           !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
                if (cfg->speaker_outs) {
                        cfg->line_outs = cfg->speaker_outs;
                        memcpy(cfg->line_out_pins, cfg->speaker_pins,
@@ -4847,21 +4933,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
                }
        }
 
-       /* Reorder the surround channels
-        * ALSA sequence is front/surr/clfe/side
-        * HDA sequence is:
-        *    4-ch: front/surr  =>  OK as it is
-        *    6-ch: front/clfe/surr
-        *    8-ch: front/clfe/rear/side|fc
-        */
-       switch (cfg->line_outs) {
-       case 3:
-       case 4:
-               nid = cfg->line_out_pins[1];
-               cfg->line_out_pins[1] = cfg->line_out_pins[2];
-               cfg->line_out_pins[2] = nid;
-               break;
-       }
+       reorder_outputs(cfg->line_outs, cfg->line_out_pins);
+       reorder_outputs(cfg->hp_outs, cfg->hp_pins);
+       reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
 
        sort_autocfg_input_pins(cfg);
 
@@ -4899,7 +4973,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
 
        return 0;
 }
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_def_config);
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
 
 int snd_hda_get_input_pin_attr(unsigned int def_conf)
 {
@@ -5157,30 +5231,6 @@ void snd_array_free(struct snd_array *array)
 }
 EXPORT_SYMBOL_HDA(snd_array_free);
 
-/**
- * snd_print_pcm_rates - Print the supported PCM rates to the string buffer
- * @pcm: PCM caps bits
- * @buf: the string buffer to write
- * @buflen: the max buffer length
- *
- * used by hda_proc.c and hda_eld.c
- */
-void snd_print_pcm_rates(int pcm, char *buf, int buflen)
-{
-       static unsigned int rates[] = {
-               8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200,
-               96000, 176400, 192000, 384000
-       };
-       int i, j;
-
-       for (i = 0, j = 0; i < ARRAY_SIZE(rates); i++)
-               if (pcm & (1 << i))
-                       j += snprintf(buf + j, buflen - j,  " %d", rates[i]);
-
-       buf[j] = '\0'; /* necessary when j == 0 */
-}
-EXPORT_SYMBOL_HDA(snd_print_pcm_rates);
-
 /**
  * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
  * @pcm: PCM caps bits
@@ -5222,6 +5272,8 @@ static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
                return "Mic";
        case SND_JACK_LINEOUT:
                return "Line-out";
+       case SND_JACK_LINEIN:
+               return "Line-in";
        case SND_JACK_HEADSET:
                return "Headset";
        case SND_JACK_VIDEOOUT: