Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / sound / pci / hda / hda_eld.c
index 8e575bb..fcad5ec 100644 (file)
@@ -32,14 +32,6 @@ enum eld_versions {
        ELD_VER_PARTIAL         = 31,
 };
 
-static char *eld_versoin_names[32] = {
-       "reserved",
-       "reserved",
-       "CEA-861D or below",
-       [3 ... 30] = "reserved",
-       [31] = "partial"
-};
-
 enum cea_edid_versions {
        CEA_EDID_VER_NONE       = 0,
        CEA_EDID_VER_CEA861     = 1,
@@ -48,14 +40,6 @@ enum cea_edid_versions {
        CEA_EDID_VER_RESERVED   = 4,
 };
 
-static char *cea_edid_version_names[8] = {
-       "no CEA EDID Timing Extension block present",
-       "CEA-861",
-       "CEA-861-A",
-       "CEA-861-B, C or D",
-       [4 ... 7] = "reserved"
-};
-
 static char *cea_speaker_allocation_names[] = {
        /*  0 */ "FL/FR",
        /*  1 */ "LFE",
@@ -72,7 +56,7 @@ static char *cea_speaker_allocation_names[] = {
 
 static char *eld_connection_type_names[4] = {
        "HDMI",
-       "Display Port",
+       "DisplayPort",
        "2-reserved",
        "3-reserved"
 };
@@ -168,11 +152,11 @@ static unsigned char hdmi_get_eld_byte(struct hda_codec *codec, hda_nid_t nid,
                                        AC_VERB_GET_HDMI_ELDD, byte_index);
 
 #ifdef BE_PARANOID
-       printk(KERN_INFO "ELD data byte %d: 0x%x\n", byte_index, val);
+       printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
 #endif
 
        if ((val & AC_ELDD_ELD_VALID) == 0) {
-               snd_printd(KERN_INFO "Invalid ELD data byte %d\n",
+               snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n",
                                                                byte_index);
                val = 0;
        }
@@ -208,7 +192,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a,
        switch (a->format) {
        case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
                snd_printd(KERN_INFO
-                               "audio coding type 0 not expected in ELD\n");
+                               "HDMI: audio coding type 0 not expected\n");
                break;
 
        case AUDIO_CODING_TYPE_LPCM:
@@ -254,7 +238,7 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a,
                if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
                    a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
                        snd_printd(KERN_INFO
-                               "audio coding xtype %d not expected in ELD\n",
+                               "HDMI: audio coding xtype %d not expected\n",
                                a->format);
                        a->format = 0;
                } else
@@ -276,7 +260,8 @@ static int hdmi_update_eld(struct hdmi_eld *e,
        e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
        if (e->eld_ver != ELD_VER_CEA_861D &&
            e->eld_ver != ELD_VER_PARTIAL) {
-               snd_printd(KERN_INFO "Unknown ELD version %d\n", e->eld_ver);
+               snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n",
+                                                               e->eld_ver);
                goto out_fail;
        }
 
@@ -300,17 +285,17 @@ static int hdmi_update_eld(struct hdmi_eld *e,
        e->product_id     = get_unaligned_le16(buf + 18);
 
        if (mnl > ELD_MAX_MNL) {
-               snd_printd(KERN_INFO "MNL is reserved value %d\n", mnl);
+               snd_printd(KERN_INFO "HDMI: MNL is reserved value %d\n", mnl);
                goto out_fail;
        } else if (ELD_FIXED_BYTES + mnl > size) {
-               snd_printd(KERN_INFO "out of range MNL %d\n", mnl);
+               snd_printd(KERN_INFO "HDMI: out of range MNL %d\n", mnl);
                goto out_fail;
        } else
                strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl);
 
        for (i = 0; i < e->sad_count; i++) {
                if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
-                       snd_printd(KERN_INFO "out of range SAD %d\n", i);
+                       snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i);
                        goto out_fail;
                }
                hdmi_update_short_audio_desc(e->sad + i,
@@ -339,7 +324,8 @@ static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
        present = (present & AC_PINSENSE_PRESENCE);
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
-       printk(KERN_INFO "pinp = %d, eldv = %d\n", !!present, !!eldv);
+       printk(KERN_INFO "HDMI: sink_present = %d, eld_valid = %d\n",
+                       !!present, !!eldv);
 #endif
 
        return eldv && present;
@@ -365,11 +351,11 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
        size = snd_hdmi_get_eld_size(codec, nid);
        if (size == 0) {
                /* wfg: workaround for ASUS P5E-VM HDMI board */
-               snd_printd(KERN_INFO "ELD buf size is 0, force 128\n");
+               snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
                size = 128;
        }
        if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) {
-               snd_printd(KERN_INFO "Invalid ELD buf size %d\n", size);
+               snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
                return -ERANGE;
        }
 
@@ -389,22 +375,27 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
 static void hdmi_show_short_audio_desc(struct cea_sad *a)
 {
        char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+       char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
 
-       printk(KERN_INFO "coding type: %s\n",
-                                       cea_audio_coding_type_names[a->format]);
-       printk(KERN_INFO "channels: %d\n", a->channels);
+       if (!a->format)
+               return;
 
        snd_print_pcm_rates(a->rates, buf, sizeof(buf));
-       printk(KERN_INFO "sampling rates: %s\n", buf);
 
        if (a->format == AUDIO_CODING_TYPE_LPCM)
-               printk(KERN_INFO "sample bits: 0x%x\n", a->sample_bits);
-
-       if (a->max_bitrate)
-               printk(KERN_INFO "max bitrate: %d\n", a->max_bitrate);
-
-       if (a->profile)
-               printk(KERN_INFO "profile: %d\n", a->profile);
+               snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2 - 8));
+       else if (a->max_bitrate)
+               snprintf(buf2, sizeof(buf2),
+                               ", max bitrate = %d", a->max_bitrate);
+       else
+               buf2[0] = '\0';
+
+       printk(KERN_INFO "HDMI: supports coding type %s:"
+                       " channels = %d, rates =%s%s\n",
+                       cea_audio_coding_type_names[a->format],
+                       a->channels,
+                       buf,
+                       buf2);
 }
 
 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
@@ -422,29 +413,16 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen)
 void snd_hdmi_show_eld(struct hdmi_eld *e)
 {
        int i;
-       char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
 
-       printk(KERN_INFO "ELD buffer size  is %d\n", e->eld_size);
-       printk(KERN_INFO "ELD baseline len is %d*4\n", e->baseline_len);
-       printk(KERN_INFO "vendor block len is %d\n",
-                                       e->eld_size - e->baseline_len * 4 - 4);
-       printk(KERN_INFO "ELD version      is %s\n",
-                                       eld_versoin_names[e->eld_ver]);
-       printk(KERN_INFO "CEA EDID version is %s\n",
-                               cea_edid_version_names[e->cea_edid_ver]);
-       printk(KERN_INFO "manufacture id   is 0x%x\n", e->manufacture_id);
-       printk(KERN_INFO "product id       is 0x%x\n", e->product_id);
-       printk(KERN_INFO "port id          is 0x%llx\n", (long long)e->port_id);
-       printk(KERN_INFO "HDCP support     is %d\n", e->support_hdcp);
-       printk(KERN_INFO "AI support       is %d\n", e->support_ai);
-       printk(KERN_INFO "SAD count        is %d\n", e->sad_count);
-       printk(KERN_INFO "audio sync delay is %x\n", e->aud_synch_delay);
-       printk(KERN_INFO "connection type  is %s\n",
-                               eld_connection_type_names[e->conn_type]);
-       printk(KERN_INFO "monitor name     is %s\n", e->monitor_name);
+       printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n",
+                       e->monitor_name,
+                       eld_connection_type_names[e->conn_type]);
 
-       snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
-       printk(KERN_INFO "speaker allocations: (0x%x)%s\n", e->spk_alloc, buf);
+       if (e->spk_alloc) {
+               char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+               snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+               printk(KERN_INFO "HDMI: available speakers:%s\n", buf);
+       }
 
        for (i = 0; i < e->sad_count; i++)
                hdmi_show_short_audio_desc(e->sad + i);
@@ -484,8 +462,22 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
        struct hdmi_eld *e = entry->private_data;
        char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
        int i;
-
-       snd_iprintf(buffer, "monitor name\t\t%s\n", e->monitor_name);
+       static char *eld_versoin_names[32] = {
+               "reserved",
+               "reserved",
+               "CEA-861D or below",
+               [3 ... 30] = "reserved",
+               [31] = "partial"
+       };
+       static char *cea_edid_version_names[8] = {
+               "no CEA EDID Timing Extension block present",
+               "CEA-861",
+               "CEA-861-A",
+               "CEA-861-B, C or D",
+               [4 ... 7] = "reserved"
+       };
+
+       snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
        snd_iprintf(buffer, "connection_type\t\t%s\n",
                                eld_connection_type_names[e->conn_type]);
        snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
@@ -508,6 +500,66 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
                hdmi_print_sad_info(i, e->sad + i, buffer);
 }
 
+static void hdmi_write_eld_info(struct snd_info_entry *entry,
+                               struct snd_info_buffer *buffer)
+{
+       struct hdmi_eld *e = entry->private_data;
+       char line[64];
+       char name[64];
+       char *sname;
+       long long val;
+       int n;
+
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "%s %llx", name, &val) != 2)
+                       continue;
+               /*
+                * We don't allow modification to these fields:
+                *      monitor_name manufacture_id product_id
+                *      eld_version edid_version
+                */
+               if (!strcmp(name, "connection_type"))
+                       e->conn_type = val;
+               else if (!strcmp(name, "port_id"))
+                       e->port_id = val;
+               else if (!strcmp(name, "support_hdcp"))
+                       e->support_hdcp = val;
+               else if (!strcmp(name, "support_ai"))
+                       e->support_ai = val;
+               else if (!strcmp(name, "audio_sync_delay"))
+                       e->aud_synch_delay = val;
+               else if (!strcmp(name, "speakers"))
+                       e->spk_alloc = val;
+               else if (!strcmp(name, "sad_count"))
+                       e->sad_count = val;
+               else if (!strncmp(name, "sad", 3)) {
+                       sname = name + 4;
+                       n = name[3] - '0';
+                       if (name[4] >= '0' && name[4] <= '9') {
+                               sname++;
+                               n = 10 * n + name[4] - '0';
+                       }
+                       if (n < 0 || n > 31) /* double the CEA limit */
+                               continue;
+                       if (!strcmp(sname, "_coding_type"))
+                               e->sad[n].format = val;
+                       else if (!strcmp(sname, "_channels"))
+                               e->sad[n].channels = val;
+                       else if (!strcmp(sname, "_rates"))
+                               e->sad[n].rates = val;
+                       else if (!strcmp(sname, "_bits"))
+                               e->sad[n].sample_bits = val;
+                       else if (!strcmp(sname, "_max_bitrate"))
+                               e->sad[n].max_bitrate = val;
+                       else if (!strcmp(sname, "_profile"))
+                               e->sad[n].profile = val;
+                       if (n >= e->sad_count)
+                               e->sad_count = n + 1;
+               }
+       }
+}
+
+
 int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
 {
        char name[32];
@@ -520,7 +572,19 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld)
                return err;
 
        snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+       entry->c.text.write = hdmi_write_eld_info;
+       entry->mode |= S_IWUSR;
+       eld->proc_entry = entry;
+
        return 0;
 }
 
-#endif
+void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
+{
+       if (!codec->bus->shutdown && eld->proc_entry) {
+               snd_device_free(codec->bus->card, eld->proc_entry);
+               eld->proc_entry = NULL;
+       }
+}
+
+#endif /* CONFIG_PROC_FS */