staticunsignedint sad_rate_mask(const u8 *sad)
{ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) { case HDMI_AUDIO_CODING_TYPE_PCM: return sad[1] & SAD1_RATE_MASK; case HDMI_AUDIO_CODING_TYPE_AC3: case HDMI_AUDIO_CODING_TYPE_DTS: return map_rate_families(sad,
SAD1_RATE_32000_MASK,
SAD1_RATE_44100_MASK,
SAD1_RATE_48000_MASK); case HDMI_AUDIO_CODING_TYPE_EAC3: case HDMI_AUDIO_CODING_TYPE_DTS_HD: case HDMI_AUDIO_CODING_TYPE_MLP: return map_rate_families(sad,
0,
SAD1_RATE_176400_MASK,
SAD1_RATE_192000_MASK); default: /* TODO adjust for other compressed formats as well */ return sad[1] & SAD1_RATE_MASK;
}
}
staticunsignedint sad_max_channels(const u8 *sad)
{ switch (FIELD_GET(SAD0_FORMAT_MASK, sad[0])) { case HDMI_AUDIO_CODING_TYPE_PCM: return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]); case HDMI_AUDIO_CODING_TYPE_AC3: case HDMI_AUDIO_CODING_TYPE_DTS: case HDMI_AUDIO_CODING_TYPE_EAC3: return 2; case HDMI_AUDIO_CODING_TYPE_DTS_HD: case HDMI_AUDIO_CODING_TYPE_MLP: return 8; default: /* TODO adjust for other compressed formats as well */ return 1 + FIELD_GET(SAD0_CHANNELS_MASK, sad[0]);
}
}
sad = drm_eld_sad(eld); if (sad) { unsignedint rate_mask = 0;
/* Convert the rate interval to a mask */
r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); for (i = 0; i < ARRAY_SIZE(eld_rates); i++) if (r->min <= eld_rates[i] && r->max >= eld_rates[i])
rate_mask |= BIT(i);
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) if (rate_mask & sad_rate_mask(sad))
t.max = max(t.max, sad_max_channels(sad));
}
return snd_interval_refine(c, &t);
}
int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld)
{ int ret;
ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
eld_limit_rates, eld,
SNDRV_PCM_HW_PARAM_CHANNELS, -1); if (ret < 0) return ret;
ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
eld_limit_channels, eld,
SNDRV_PCM_HW_PARAM_RATE, -1);
a->format = GRAB_BITS(buf, 0, 3, 4); switch (a->format) { case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
dev_info(dev, "HDMI: audio coding type 0 not expected\n"); break;
case AUDIO_CODING_TYPE_LPCM:
val = GRAB_BITS(buf, 2, 0, 3); 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;
/* * Be careful, ELD buf could be totally rubbish!
*/ int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e, constunsignedchar *buf, int size)
{ int mnl; int i;
/* 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) {
dev_info(dev, "HDMI: MNL is reserved value %d\n", mnl); goto out_fail;
} elseif (ELD_FIXED_BYTES + mnl > size) {
dev_info(dev, "HDMI: out of range MNL %d\n", mnl); goto out_fail;
} else
strscpy(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) {
dev_info(dev, "HDMI: out of range SAD %d\n", i); goto out_fail;
}
hdmi_update_short_audio_desc(dev, 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;
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);
hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
if (a->format == AUDIO_CODING_TYPE_LPCM) {
eld_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",
i, a->max_bitrate);
if (a->profile)
snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
}
void snd_print_eld_info(struct snd_parsed_hdmi_eld *e, struct snd_info_buffer *buffer)
{ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; staticconstchar * const eld_version_names[32] = { "reserved", "reserved", "CEA-861D or below",
[3 ... 30] = "reserved",
[31] = "partial"
}; staticconstchar * const 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"
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.