int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) { int i; int ret; int size; unsigned char *buf; if (!hdmi_eld_valid(codec, nid)) return -ENOENT; size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ 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 "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; for (i = 0; i < size; i++) buf[i] = hdmi_get_eld_byte(codec, nid, i); ret = hdmi_update_eld(eld, buf, size); kfree(buf); return ret; }
int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) { int i; int ret; int size; unsigned char *buf; if (!hdmi_eld_valid(codec, nid)) return -ENOENT; size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ 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 "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } if (!eld->lpcm_sad_ready) hdmi_update_lpcm_sad_eld(codec, nid, eld, size); codec->recv_dec_cap = 0; for (i = 0; i < eld->sad_count; i++) { if (eld->sad[i].format == AUDIO_CODING_TYPE_AC3) { codec->recv_dec_cap |= (1<<AUDIO_CODING_TYPE_AC3); } else if (eld->sad[i].format == AUDIO_CODING_TYPE_DTS) { codec->recv_dec_cap |= (1<<AUDIO_CODING_TYPE_DTS); } } buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; for (i = 0; i < size; i++) buf[i] = hdmi_get_eld_byte(codec, nid, i); ret = hdmi_update_eld(eld, buf, size); kfree(buf); return ret; }
/* update ELD information relevant for getting PCM info */ static int hdmi_update_lpcm_sad_eld (struct hda_codec *codec, hda_nid_t nid, struct hdmi_eld *e, int size) { int i, j; u32 val, sad_base; struct cea_sad *a; snd_printd(KERN_INFO "hdmi_update_lpcm_sad_eld\n"); val = hdmi_get_eld_byte(codec, nid, 0); e->eld_ver = GET_BITS(val, 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; } val = hdmi_get_eld_byte(codec, nid, 4); sad_base = GET_BITS(val, 0, 5); sad_base += ELD_FIXED_BYTES; val = hdmi_get_eld_byte(codec, nid, 5); e->sad_count = GET_BITS(val, 4, 4); for (i = 0; i < e->sad_count; i++, sad_base += 3) { if ((sad_base + 3) > size) { snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); goto out_fail; } a = &e->sad[i]; val = hdmi_get_eld_byte(codec, nid, sad_base); a->format = GET_BITS(val, 3, 4); a->channels = GET_BITS(val, 0, 3); a->channels++; a->rates = 0; a->sample_bits = 0; a->max_bitrate = 0; if (a->format != AUDIO_CODING_TYPE_LPCM) continue; val = hdmi_get_eld_byte(codec, nid, sad_base + 1); val = GET_BITS(val, 0, 7); for (j = 0; j < 7; j++) if (val & (1 << j)) a->rates |= cea_sampling_frequencies[j + 1]; val = hdmi_get_eld_byte(codec, nid, sad_base + 2); val = GET_BITS(val, 0, 3); for (j = 0; j < 3; j++) if (val & (1 << j)) a->sample_bits |= cea_sample_sizes[j + 1]; } e->lpcm_sad_ready = 1; return 0; out_fail: e->eld_ver = 0; return -EINVAL; }
/* update ELD information relevant for getting PCM info */ int hdmi_update_lpcm_sad_eld (struct hda_codec *codec, hda_nid_t nid, struct hdmi_eld *e) { int i, j; u32 val, sad_base; int size; struct cea_sad *a; size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); size = 128; } if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } val = hdmi_get_eld_byte(codec, nid, 0); e->info.eld_ver = GET_BITS(val, 3, 5); if (e->info.eld_ver != ELD_VER_CEA_861D && e->info.eld_ver != ELD_VER_PARTIAL) { snd_printd(KERN_INFO "HDMI: Unknown ELD version %d\n", e->info.eld_ver); goto out_fail; } val = hdmi_get_eld_byte(codec, nid, 4); sad_base = GET_BITS(val, 0, 5); sad_base += ELD_FIXED_BYTES; val = hdmi_get_eld_byte(codec, nid, 5); e->info.sad_count = GET_BITS(val, 4, 4); for (i = 0; i < e->info.sad_count; i++, sad_base += 3) { if ((sad_base + 3) > size) { snd_printd(KERN_INFO "HDMI: out of range SAD %d\n", i); goto out_fail; } a = &e->info.sad[i]; val = hdmi_get_eld_byte(codec, nid, sad_base); a->format = GET_BITS(val, 3, 4); a->channels = GET_BITS(val, 0, 3); a->channels++; a->rates = 0; a->sample_bits = 0; a->max_bitrate = 0; if (a->format != AUDIO_CODING_TYPE_LPCM) continue; val = hdmi_get_eld_byte(codec, nid, sad_base + 1); val = GET_BITS(val, 0, 7); for (j = 0; j < 7; j++) if (val & (1 << j)) a->rates |= cea_sampling_frequencies[j + 1]; val = hdmi_get_eld_byte(codec, nid, sad_base + 2); val = GET_BITS(val, 0, 3); for (j = 0; j < 3; j++) if (val & (1 << j)) a->sample_bits |= cea_sample_sizes[j + 1]; } e->info.lpcm_sad_ready = 1; codec->recv_dec_cap = 0; codec->max_pcm_channels = 0; for (i = 0; i < e->info.sad_count; i++) { if (e->info.sad[i].format == AUDIO_CODING_TYPE_AC3) { codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_AC3); } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_DTS) { codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_DTS); } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_EAC3) { codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_EAC3); } else if (e->info.sad[i].format == AUDIO_CODING_TYPE_LPCM) { codec->max_pcm_channels = e->info.sad[i].channels > codec->max_pcm_channels ? e->info.sad[i].channels : codec->max_pcm_channels; } } return 0; out_fail: e->info.eld_ver = 0; return -EINVAL; }