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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/* 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;
}
Beispiel #4
0
/* 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;
}