/* * 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; }
/* * 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; }