ALSA: ELD proc interface for HDMI sinks
authorWu Fengguang <wfg@linux.intel.com>
Tue, 18 Nov 2008 03:47:53 +0000 (11:47 +0800)
committerTakashi Iwai <tiwai@suse.de>
Tue, 18 Nov 2008 06:39:12 +0000 (07:39 +0100)
Create /proc/asound/card<card_no>/eld#<codec_no> to reflect the audio
configurations and capabilities of the attached HDMI sink.

Some notes:

- Shall we show an empty file if the ELD content is not valid?
  Well it's not that simple. There could be partially populated ELD,
  and there may be malformed ELD provided by buggy drivers/monitors.
  So expose ELD as it is.

- The ELD retrieval routines rely on the Intel HDA interface,
  others are/could be universal and independent ones.

- How do we name the proc file?
  If there are going to be two HDMI pins per codec, then the current naming
  scheme (eld#<codec no>) will fail. Luckily the user space dependencies should
  be minimal, so it would be trivial to do the rename if that happens.

- The ELD proc file content is designed to be easy for scripts and human reading.
  Its lines all have the pattern:
  <item_name>\t[\t]*<item_value>
  where <item_name> is a keyword in c language, while <item_value> could be any
  contents, including white spaces. <item_value> could also be a null value.

Signed-off-by: Wu Fengguang <wfg@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_eld.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_intelhdmi.c

index a69a7e87d26a8cd68b74d50ff8248537bb75a987..7fa065cd1d9cf34bbfb36b02e3d0b2d5f17a18c1 100644 (file)
@@ -452,3 +452,77 @@ void snd_hdmi_show_eld(struct sink_eld *e)
        for (i = 0; i < e->sad_count; i++)
                hdmi_show_short_audio_desc(e->sad + i);
 }
+
+#ifdef CONFIG_PROC_FS
+
+static void hdmi_print_sad_info(int i, struct cea_sad *a,
+                               struct snd_info_buffer *buffer)
+{
+       char buf[80];
+
+       snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
+                       i, a->format, cea_audio_coding_type_names[a->format]);
+       snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+
+       snd_print_pcm_rates(a->rates, buf, sizeof(buf));
+       snd_iprintf(buffer, "sad%d_sampling_rates\t[0x%x] %s\n",
+                       i, a->rates, buf);
+
+       if (a->format == AUDIO_CODING_TYPE_LPCM)
+               snd_iprintf(buffer, "sad%d_sample_bits\t0x%x\n",
+                                                       i, a->sample_bits);
+
+       if (a->max_bitrate)
+               snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
+                                                       i, a->max_bitrate);
+
+       if (a->profile)
+               snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+static void hdmi_print_eld_info(struct snd_info_entry *entry,
+                               struct snd_info_buffer *buffer)
+{
+       struct sink_eld *e = entry->private_data;
+       char buf[HDMI_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+       int i;
+
+       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,
+                                       eld_versoin_names[e->eld_ver]);
+       snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
+                               cea_edid_version_names[e->cea_edid_ver]);
+       snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+       snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+       snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+       snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+       snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+       snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
+
+       hdmi_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+       snd_iprintf(buffer, "speakers\t\t[0x%x] %s\n", e->spk_alloc, buf);
+
+       snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+       for (i = 0; i < e->sad_count; i++)
+               hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld)
+{
+       char name[32];
+       struct snd_info_entry *entry;
+       int err;
+
+       snprintf(name, sizeof(name), "eld#%d", codec->addr);
+       err = snd_card_proc_new(codec->bus->card, name, &entry);
+       if (err < 0)
+               return err;
+
+       snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
+       return 0;
+}
+
+#endif
index e1b76686672abb59e1d995788079f4db88694c63..02ac7321e5e4de408ae6b9f14009f359c0a9ce11 100644 (file)
@@ -484,4 +484,13 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
 int snd_hdmi_get_eld(struct sink_eld *, struct hda_codec *, hda_nid_t);
 void snd_hdmi_show_eld(struct sink_eld *eld);
 
+#ifdef CONFIG_PROC_FS
+int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld);
+#else
+inline int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld)
+{
+       return 0;
+}
+#endif
+
 #endif /* __SOUND_HDA_LOCAL_H */
index 489278d3d773da84d7457158ca8a79783d9f9379..c95abc47614f0ada3f05fbd6d6bb4c3a74e54242 100644 (file)
@@ -446,6 +446,8 @@ static int patch_intel_hdmi(struct hda_codec *codec)
        codec->spec = spec;
        codec->patch_ops = intel_hdmi_patch_ops;
 
+       snd_hda_eld_proc_new(codec, &spec->sink);
+
        return 0;
 }