ALSA: hda - Overwrite pin config on intel DG45ID board.
[safe/jmp/linux-2.6] / sound / pci / hda / hda_proc.c
index 7b38179..c9afc04 100644 (file)
 #include "hda_codec.h"
 #include "hda_local.h"
 
+static char *bits_names(unsigned int bits, char *names[], int size)
+{
+       int i, n;
+       static char buf[128];
+
+       for (i = 0, n = 0; i < size; i++) {
+               if (bits & (1U<<i) && names[i])
+                       n += snprintf(buf + n, sizeof(buf) - n, " %s",
+                                     names[i]);
+       }
+       buf[n] = '\0';
+
+       return buf;
+}
+
 static const char *get_wid_type_name(unsigned int wid_value)
 {
        static char *names[16] = {
@@ -46,6 +61,41 @@ static const char *get_wid_type_name(unsigned int wid_value)
                return "UNKNOWN Widget";
 }
 
+static void print_nid_mixers(struct snd_info_buffer *buffer,
+                            struct hda_codec *codec, hda_nid_t nid)
+{
+       int i;
+       struct hda_nid_item *items = codec->mixers.list;
+       struct snd_kcontrol *kctl;
+       for (i = 0; i < codec->mixers.used; i++) {
+               if (items[i].nid == nid) {
+                       kctl = items[i].kctl;
+                       snd_iprintf(buffer,
+                         "  Control: name=\"%s\", index=%i, device=%i\n",
+                         kctl->id.name, kctl->id.index, kctl->id.device);
+               }
+       }
+}
+
+static void print_nid_pcms(struct snd_info_buffer *buffer,
+                          struct hda_codec *codec, hda_nid_t nid)
+{
+       int pcm, type;
+       struct hda_pcm *cpcm;
+       for (pcm = 0; pcm < codec->num_pcms; pcm++) {
+               cpcm = &codec->pcm_info[pcm];
+               for (type = 0; type < 2; type++) {
+                       if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL)
+                               continue;
+                       snd_iprintf(buffer, "  Device: name=\"%s\", "
+                                   "type=\"%s\", device=%i\n",
+                                   cpcm->name,
+                                   snd_hda_pcm_type_name[cpcm->pcm_type],
+                                   cpcm->pcm->device);
+               }
+       }
+}
+
 static void print_amp_caps(struct snd_info_buffer *buffer,
                           struct hda_codec *codec, hda_nid_t nid, int dir)
 {
@@ -190,9 +240,14 @@ static void print_pin_caps(struct snd_info_buffer *buffer,
                /* Realtek uses this bit as a different meaning */
                if ((codec->vendor_id >> 16) == 0x10ec)
                        snd_iprintf(buffer, " R/L");
-               else
+               else {
+                       if (caps & AC_PINCAP_HBR)
+                               snd_iprintf(buffer, " HBR");
                        snd_iprintf(buffer, " HDMI");
+               }
        }
+       if (caps & AC_PINCAP_DP)
+               snd_iprintf(buffer, " DP");
        if (caps & AC_PINCAP_TRIG_REQ)
                snd_iprintf(buffer, " Trigger");
        if (caps & AC_PINCAP_IMP_SENSE)
@@ -363,8 +418,24 @@ static const char *get_pwr_state(u32 state)
 static void print_power_state(struct snd_info_buffer *buffer,
                              struct hda_codec *codec, hda_nid_t nid)
 {
+       static char *names[] = {
+               [ilog2(AC_PWRST_D0SUP)]         = "D0",
+               [ilog2(AC_PWRST_D1SUP)]         = "D1",
+               [ilog2(AC_PWRST_D2SUP)]         = "D2",
+               [ilog2(AC_PWRST_D3SUP)]         = "D3",
+               [ilog2(AC_PWRST_D3COLDSUP)]     = "D3cold",
+               [ilog2(AC_PWRST_S3D3COLDSUP)]   = "S3D3cold",
+               [ilog2(AC_PWRST_CLKSTOP)]       = "CLKSTOP",
+               [ilog2(AC_PWRST_EPSS)]          = "EPSS",
+       };
+
+       int sup = snd_hda_param_read(codec, nid, AC_PAR_POWER_STATE);
        int pwr = snd_hda_codec_read(codec, nid, 0,
                                     AC_VERB_GET_POWER_STATE, 0);
+       if (sup)
+               snd_iprintf(buffer, "  Power states: %s\n",
+                           bits_names(sup, names, ARRAY_SIZE(names)));
+
        snd_iprintf(buffer, "  Power: setting=%s, actual=%s\n",
                    get_pwr_state(pwr & AC_PWRST_SETTING),
                    get_pwr_state((pwr & AC_PWRST_ACTUAL) >>
@@ -399,7 +470,10 @@ static void print_conn_list(struct snd_info_buffer *buffer,
 {
        int c, curr = -1;
 
-       if (conn_len > 1 && wid_type != AC_WID_AUD_MIX)
+       if (conn_len > 1 &&
+           wid_type != AC_WID_AUD_MIX &&
+           wid_type != AC_WID_VOL_KNB &&
+           wid_type != AC_WID_POWER)
                curr = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_CONNECT_SEL, 0);
        snd_iprintf(buffer, "  Connection: %d\n", conn_len);
@@ -454,6 +528,7 @@ static void print_gpio(struct snd_info_buffer *buffer,
                            (data & (1<<i)) ? 1 : 0,
                            (unsol & (1<<i)) ? 1 : 0);
        /* FIXME: add GPO and GPI pin information */
+       print_nid_mixers(buffer, codec, nid);
 }
 
 static void print_codec_info(struct snd_info_entry *entry,
@@ -463,11 +538,16 @@ static void print_codec_info(struct snd_info_entry *entry,
        hda_nid_t nid;
        int i, nodes;
 
-       snd_iprintf(buffer, "Codec: %s\n",
-                   codec->name ? codec->name : "Not Set");
+       snd_iprintf(buffer, "Codec: ");
+       if (codec->vendor_name && codec->chip_name)
+               snd_iprintf(buffer, "%s %s\n",
+                           codec->vendor_name, codec->chip_name);
+       else
+               snd_iprintf(buffer, "Not Set\n");
        snd_iprintf(buffer, "Address: %d\n", codec->addr);
-       snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
-       snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
+       snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id);
+       snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id);
+       snd_iprintf(buffer, "Subsystem Id: 0x%08x\n", codec->subsystem_id);
        snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
 
        if (codec->mfg)
@@ -493,22 +573,21 @@ static void print_codec_info(struct snd_info_entry *entry,
        }
 
        print_gpio(buffer, codec, codec->afg);
+       if (codec->proc_widget_hook)
+               codec->proc_widget_hook(buffer, codec, codec->afg);
 
        for (i = 0; i < nodes; i++, nid++) {
                unsigned int wid_caps =
                        snd_hda_param_read(codec, nid,
                                           AC_PAR_AUDIO_WIDGET_CAP);
-               unsigned int wid_type =
-                       (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+               unsigned int wid_type = get_wcaps_type(wid_caps);
                hda_nid_t conn[HDA_MAX_CONNECTIONS];
                int conn_len = 0;
 
                snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid,
                            get_wid_type_name(wid_type), wid_caps);
                if (wid_caps & AC_WCAP_STEREO) {
-                       unsigned int chans;
-                       chans = (wid_caps & AC_WCAP_CHAN_CNT_EXT) >> 13;
-                       chans = ((chans << 1) | 1) + 1;
+                       unsigned int chans = get_wcaps_channels(wid_caps);
                        if (chans == 2)
                                snd_iprintf(buffer, " Stereo");
                        else
@@ -529,6 +608,9 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, " CP");
                snd_iprintf(buffer, "\n");
 
+               print_nid_mixers(buffer, codec, nid);
+               print_nid_pcms(buffer, codec, nid);
+
                /* volume knob is a special widget that always have connection
                 * list
                 */
@@ -551,8 +633,14 @@ static void print_codec_info(struct snd_info_entry *entry,
                        snd_iprintf(buffer, "  Amp-Out caps: ");
                        print_amp_caps(buffer, codec, nid, HDA_OUTPUT);
                        snd_iprintf(buffer, "  Amp-Out vals: ");
-                       print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
-                                      wid_caps & AC_WCAP_STEREO, 1);
+                       if (wid_type == AC_WID_PIN &&
+                           codec->pin_amp_workaround)
+                               print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+                                              wid_caps & AC_WCAP_STEREO,
+                                              conn_len);
+                       else
+                               print_amp_vals(buffer, codec, nid, HDA_OUTPUT,
+                                              wid_caps & AC_WCAP_STEREO, 1);
                }
 
                switch (wid_type) {