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 hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size) { int i; int ret = 0; int size; /* * ELD size is initialized to zero in caller function. If no errors and * ELD is valid, actual eld_size is assigned. */ 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; } /* set ELD buffer */ for (i = 0; i < size; i++) { unsigned int val = hdmi_get_eld_data(codec, nid, i); /* * Graphics driver might be writing to ELD buffer right now. * Just abort. The caller will repoll after a while. */ if (!(val & AC_ELDD_ELD_VALID)) { snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", i); ret = -EINVAL; goto error; } val &= AC_ELDD_ELD_DATA; /* * The first byte cannot be zero. This can happen on some DVI * connections. Some Intel chips may also need some 250ms delay * to return non-zero ELD data, even when the graphics driver * correctly writes ELD content before setting ELD_valid bit. */ if (!val && !i) { snd_printdd(KERN_INFO "HDMI: 0 ELD data\n"); ret = -EINVAL; goto error; } buf[i] = val; } *eld_size = size; error: 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; 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); buf = kmalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; for (i = 0; i < size; i++) { unsigned int val = hdmi_get_eld_data(codec, nid, i); if (!(val & AC_ELDD_ELD_VALID)) { if (!i) { snd_printd(KERN_INFO "HDMI: invalid ELD data\n"); ret = -EINVAL; goto error; } snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", i); val = 0; } else val &= AC_ELDD_ELD_DATA; buf[i] = val; } ret = hdmi_update_eld(eld, buf, size); codec->ac3dec_capable = false; for (i = 0; i < eld->sad_count; i++) { if (eld->sad[i].format == AUDIO_CODING_TYPE_AC3) codec->ac3dec_capable = true; } error: 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 */ 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; }
int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) { int i; int ret = 0; int size; unsigned char *buf; /* * ELD size is initialized to zero in caller function. If no errors and * ELD is valid, actual eld_size is assigned in hdmi_update_eld() */ 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; } if (!eld->lpcm_sad_ready) hdmi_update_lpcm_sad_eld(codec, nid, eld, size); /* set ELD buffer */ buf = eld->eld_buffer; codec->recv_dec_cap = 0; codec->max_pcm_channels = 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); } else if (eld->sad[i].format == AUDIO_CODING_TYPE_EAC3) { codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_EAC3); } else if (eld->sad[i].format == AUDIO_CODING_TYPE_LPCM) { codec->max_pcm_channels = eld->sad[i].channels > codec->max_pcm_channels ? eld->sad[i].channels : codec->max_pcm_channels; } } for (i = 0; i < size; i++) { unsigned int val = hdmi_get_eld_data(codec, nid, i); /* * Graphics driver might be writing to ELD buffer right now. * Just abort. The caller will repoll after a while. */ if (!(val & AC_ELDD_ELD_VALID)) { snd_printd(KERN_INFO "HDMI: invalid ELD data byte %d\n", i); ret = -EINVAL; goto error; } val &= AC_ELDD_ELD_DATA; /* * The first byte cannot be zero. This can happen on some DVI * connections. Some Intel chips may also need some 250ms delay * to return non-zero ELD data, even when the graphics driver * correctly writes ELD content before setting ELD_valid bit. */ if (!val && !i) { snd_printdd(KERN_INFO "HDMI: 0 ELD data\n"); ret = -EINVAL; goto error; } buf[i] = val; } ret = hdmi_update_eld(eld, buf, size); error: return ret; }