/* * Be careful, ELD buf could be totally rubbish! */ 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 "HDMI: Unknown ELD version %d\n", e->eld_ver); goto out_fail; } e->eld_size = size; e->baseline_len = GRAB_BITS(buf, 2, 0, 8); mnl = GRAB_BITS(buf, 4, 0, 5); e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); e->support_ai = GRAB_BITS(buf, 5, 1, 1); e->conn_type = GRAB_BITS(buf, 5, 2, 2); e->sad_count = GRAB_BITS(buf, 5, 4, 4); e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); e->port_id = get_unaligned_le64(buf + 8); /* not specified, but the spec's tendency is little endian */ e->manufacture_id = get_unaligned_le16(buf + 16); e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_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 "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 "HDMI: out of range SAD %d\n", i); goto out_fail; } hdmi_update_short_audio_desc(e->sad + i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } return 0; out_fail: e->eld_ver = 0; return -EINVAL; }
static void hdmi_update_short_audio_desc(struct cea_sad *a, const unsigned char *buf) { int i; int val; val = GRAB_BITS(buf, 1, 0, 7); a->rates = 0; for (i = 0; i < 7; i++) if (val & (1 << i)) a->rates |= cea_sampling_frequencies[i + 1]; a->channels = GRAB_BITS(buf, 0, 0, 3); a->channels++; a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER: snd_printd(KERN_INFO "HDMI: audio coding type 0 not expected\n"); break; case AUDIO_CODING_TYPE_LPCM: val = GRAB_BITS(buf, 2, 0, 3); a->sample_bits = 0; for (i = 0; i < 3; i++) if (val & (1 << i)) a->sample_bits |= cea_sample_sizes[i + 1]; break; case AUDIO_CODING_TYPE_AC3: case AUDIO_CODING_TYPE_MPEG1: case AUDIO_CODING_TYPE_MP3: case AUDIO_CODING_TYPE_MPEG2: case AUDIO_CODING_TYPE_AACLC: case AUDIO_CODING_TYPE_DTS: case AUDIO_CODING_TYPE_ATRAC: a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); a->max_bitrate *= 8000; break; case AUDIO_CODING_TYPE_SACD: break; case AUDIO_CODING_TYPE_EAC3: break; case AUDIO_CODING_TYPE_DTS_HD: break; case AUDIO_CODING_TYPE_MLP: break; case AUDIO_CODING_TYPE_DST: break; case AUDIO_CODING_TYPE_WMAPRO: a->profile = GRAB_BITS(buf, 2, 0, 3); break; case AUDIO_CODING_TYPE_REF_CXT: a->format = GRAB_BITS(buf, 2, 3, 5); if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { snd_printd(KERN_INFO "HDMI: audio coding xtype %d not expected\n", a->format); a->format = 0; } else a->format += AUDIO_CODING_TYPE_HE_AAC - AUDIO_CODING_XTYPE_HE_AAC; break; } }
void ELD::update_sad(int index, const char *buf) { int val; cea_sad *a = m_e.sad + index; val = GRAB_BITS(buf, 1, 0, 7); a->rates = 0; for (int i = 0; i < 7; i++) if ((val & (1 << i)) != 0) a->rates |= cea_sampling_frequencies[i + 1]; a->channels = GRAB_BITS(buf, 0, 0, 3); a->channels++; a->sample_bits = 0; a->max_bitrate = 0; a->format = GRAB_BITS(buf, 0, 3, 4); m_e.formats |= 1 << a->format; switch (a->format) { case TYPE_REF_STREAM_HEADER: VBAUDIO("audio coding type 0 not expected"); break; case TYPE_LPCM: a->sample_bits = GRAB_BITS(buf, 2, 0, 3); break; case TYPE_AC3: case TYPE_MPEG1: case TYPE_MP3: case TYPE_MPEG2: case TYPE_AACLC: case TYPE_DTS: case TYPE_ATRAC: a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); a->max_bitrate *= 8000; break; case TYPE_SACD: break; case TYPE_EAC3: break; case TYPE_DTS_HD: break; case TYPE_MLP: break; case TYPE_DST: break; case TYPE_WMAPRO: a->profile = GRAB_BITS(buf, 2, 0, 3); break; case TYPE_REF_CXT: a->format = GRAB_BITS(buf, 2, 3, 5); if (a->format == XTYPE_HE_REF_CT || a->format >= XTYPE_FIRST_RESERVED) { VBAUDIO(QString("audio coding xtype %1 not expected") .arg(a->format)); a->format = 0; } else { a->format += TYPE_HE_AAC - XTYPE_HE_AAC; } break; } }
int ELD::update_eld(const char *buf, int size) { int mnl; int i; m_e.eld_ver = GRAB_BITS(buf, 0, 3, 5); if (m_e.eld_ver != ELD_VER_CEA_861D && m_e.eld_ver != ELD_VER_PARTIAL) { VBAUDIO(QString("Unknown ELD version %1").arg(m_e.eld_ver)); goto out_fail; } m_e.eld_size = size; m_e.baseline_len = GRAB_BITS(buf, 2, 0, 8); mnl = GRAB_BITS(buf, 4, 0, 5); m_e.cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); m_e.support_hdcp = GRAB_BITS(buf, 5, 0, 1); m_e.support_ai = GRAB_BITS(buf, 5, 1, 1); m_e.conn_type = GRAB_BITS(buf, 5, 2, 2); m_e.sad_count = GRAB_BITS(buf, 5, 4, 4); m_e.aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; m_e.spk_alloc = GRAB_BITS(buf, 7, 0, 7); m_e.port_id = LE_INT64(buf + 8); /* not specified, but the spec's tendency is little endian */ m_e.manufacture_id = LE_SHORT(buf + 16); m_e.product_id = LE_SHORT(buf + 18); if (mnl > ELD_MAX_MNL) { VBAUDIO(QString("MNL is reserved value %1").arg(mnl)); goto out_fail; } else if (ELD_FIXED_BYTES + mnl > size) { VBAUDIO(QString("out of range MNL %1").arg(mnl)); goto out_fail; } else { strncpy(m_e.monitor_name, (char *)buf + ELD_FIXED_BYTES, mnl + 1); m_e.monitor_name[mnl] = '\0'; } for (i = 0; i < m_e.sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { VBAUDIO(QString("out of range SAD %1").arg(i)); goto out_fail; } update_sad(i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } /* * Assume the highest speakers configuration */ if (!m_e.spk_alloc) m_e.spk_alloc = 0xffff; m_e.eld_valid = true; return 0; out_fail: m_e.eld_valid = false; return -1; }
/* * Be careful, ELD buf could be totally rubbish! */ int snd_hdmi_parse_eld(struct parsed_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 "HDMI: Unknown ELD version %d\n", e->eld_ver); goto out_fail; } e->baseline_len = GRAB_BITS(buf, 2, 0, 8); mnl = GRAB_BITS(buf, 4, 0, 5); e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); e->support_ai = GRAB_BITS(buf, 5, 1, 1); e->conn_type = GRAB_BITS(buf, 5, 2, 2); e->sad_count = GRAB_BITS(buf, 5, 4, 4); e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); e->port_id = get_unaligned_le64(buf + 8); /* not specified, but the spec's tendency is little endian */ e->manufacture_id = get_unaligned_le16(buf + 16); e->product_id = get_unaligned_le16(buf + 18); if (mnl > ELD_MAX_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 "HDMI: out of range MNL %d\n", mnl); goto out_fail; } else strlcpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); for (i = 0; i < e->sad_count; i++) { if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); goto out_fail; } hdmi_update_short_audio_desc(e->sad + i, buf + ELD_FIXED_BYTES + mnl + 3 * i); } /* * HDMI sink's ELD info cannot always be retrieved for now, e.g. * in console or for audio devices. Assume the highest speakers * configuration, to _not_ prohibit multi-channel audio playback. */ if (!e->spk_alloc) e->spk_alloc = 0xffff; return 0; out_fail: return -EINVAL; }