*/
#include <linux/init.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <asm/unaligned.h>
#include "hda_codec.h"
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,
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",
static char *eld_connection_type_names[4] = {
"HDMI",
- "Display Port",
+ "DisplayPort",
"2-reserved",
"3-reserved"
};
/* 6 */ "AAC-LC",
/* 7 */ "DTS",
/* 8 */ "ATRAC",
- /* 9 */ "DSD (1-bit audio)",
+ /* 9 */ "DSD (One Bit Audio)",
/* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
/* 11 */ "DTS-HD",
/* 12 */ "MLP (Dolby TrueHD)",
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;
}
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:
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
/*
* Be careful, ELD buf could be totally rubbish!
*/
-static int hdmi_update_sink_eld(struct sink_eld *e,
- const unsigned char *buf, int size)
+static int hdmi_update_eld(struct hdmi_eld *e,
+ const unsigned char *buf, int size)
{
int mnl;
int i;
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;
}
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,
return -EINVAL;
}
-static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid)
-{
- return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0);
-}
-
static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid)
{
int eldv;
int present;
- present = hdmi_present_sense(codec, nid);
+ present = snd_hda_pin_sense(codec, nid);
eldv = (present & AC_PINSENSE_ELDV);
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;
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
AC_DIPSIZE_ELD_BUF);
}
+EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size);
-int snd_hdmi_get_eld(struct sink_eld *eld,
+int snd_hdmi_get_eld(struct hdmi_eld *eld,
struct hda_codec *codec, hda_nid_t nid)
{
int i;
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;
}
for (i = 0; i < size; i++)
buf[i] = hdmi_get_eld_byte(codec, nid, i);
- ret = hdmi_update_sink_eld(eld, buf, size);
+ ret = hdmi_update_eld(eld, buf, size);
kfree(buf);
return ret;
}
+EXPORT_SYMBOL_HDA(snd_hdmi_get_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 frequencies: %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)
for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
if (spk_alloc & (1 << i))
- j += snprintf(buf + j, buflen - j, "%s ",
+ j += snprintf(buf + j, buflen - j, " %s",
cea_speaker_allocation_names[i]);
}
- if (j)
- j--; /* skip last space */
buf[j] = '\0'; /* necessary when j == 0 */
}
+EXPORT_SYMBOL_HDA(snd_print_channel_allocation);
-void snd_hdmi_show_eld(struct sink_eld *e)
+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);
}
+EXPORT_SYMBOL_HDA(snd_hdmi_show_eld);
#ifdef CONFIG_PROC_FS
static void hdmi_print_sad_info(int i, struct cea_sad *a,
struct snd_info_buffer *buffer)
{
- char buf[80];
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
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);
+ snd_iprintf(buffer, "sad%d_rates\t\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->format == AUDIO_CODING_TYPE_LPCM) {
+ snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
+ snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
+ i, a->sample_bits, buf);
+ }
if (a->max_bitrate)
snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
static void hdmi_print_eld_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- struct sink_eld *e = entry->private_data;
+ 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_present\t\t%d\n", e->monitor_present);
+ snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid);
+ 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,
snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
snd_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, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
hdmi_print_sad_info(i, e->sad + i, buffer);
}
-int snd_hda_eld_proc_new(struct hda_codec *codec, struct sink_eld *eld)
+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;
+ unsigned 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, "monitor_present"))
+ e->monitor_present = val;
+ else if (!strcmp(name, "eld_valid"))
+ e->eld_valid = val;
+ else 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 >= ELD_MAX_SAD)
+ 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,
+ int index)
{
char name[32];
struct snd_info_entry *entry;
int err;
- snprintf(name, sizeof(name), "eld#%d", codec->addr);
+ snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
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);
+ entry->c.text.write = hdmi_write_eld_info;
+ entry->mode |= S_IWUSR;
+ eld->proc_entry = entry;
+
return 0;
}
+EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new);
-#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;
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free);
+
+#endif /* CONFIG_PROC_FS */