Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda/hdmi: expose ELD control

Applications may want to read ELD information to
understand what codecs are supported on the HDMI
receiver and handle the a-v delay for better lip-sync.

ELD information is exposed in a device-specific
IFACE_PCM kcontrol. Tested both with amixer and
PulseAudio; with a corresponding patch passthrough modes
are enabled automagically.

ELD control size is set to zero in case of errors or
wrong configurations. No notifications are implemented
for now, it is expected that jack detection is used to
reconfigure the audio outputs.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Pierre-Louis Bossart and committed by
Takashi Iwai
14bc52b8 ef940b04

+78 -5
+8 -5
sound/pci/hda/hda_eld.c
··· 318 318 int size; 319 319 unsigned char *buf; 320 320 321 + /* 322 + * ELD size is initialized to zero in caller function. If no errors and 323 + * ELD is valid, actual eld_size is assigned in hdmi_update_eld() 324 + */ 325 + 321 326 if (!eld->eld_valid) 322 327 return -ENOENT; 323 328 ··· 332 327 snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); 333 328 size = 128; 334 329 } 335 - if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { 330 + if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { 336 331 snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); 337 332 return -ERANGE; 338 333 } 339 334 340 - buf = kmalloc(size, GFP_KERNEL); 341 - if (!buf) 342 - return -ENOMEM; 335 + /* set ELD buffer */ 336 + buf = eld->eld_buffer; 343 337 344 338 for (i = 0; i < size; i++) { 345 339 unsigned int val = hdmi_get_eld_data(codec, nid, i); ··· 360 356 ret = hdmi_update_eld(eld, buf, size); 361 357 362 358 error: 363 - kfree(buf); 364 359 return ret; 365 360 } 366 361
+2
sound/pci/hda/hda_local.h
··· 621 621 }; 622 622 623 623 #define ELD_FIXED_BYTES 20 624 + #define ELD_MAX_SIZE 256 624 625 #define ELD_MAX_MNL 16 625 626 #define ELD_MAX_SAD 16 626 627 ··· 646 645 int spk_alloc; 647 646 int sad_count; 648 647 struct cea_sad sad[ELD_MAX_SAD]; 648 + char eld_buffer[ELD_MAX_SIZE]; 649 649 #ifdef CONFIG_PROC_FS 650 650 struct snd_info_entry *proc_entry; 651 651 #endif
+68
sound/pci/hda/patch_hdmi.c
··· 324 324 return -EINVAL; 325 325 } 326 326 327 + static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, 328 + struct snd_ctl_elem_info *uinfo) 329 + { 330 + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 331 + struct hdmi_spec *spec; 332 + int pin_idx; 333 + 334 + spec = codec->spec; 335 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 336 + 337 + pin_idx = kcontrol->private_value; 338 + uinfo->count = spec->pins[pin_idx].sink_eld.eld_size; 339 + 340 + return 0; 341 + } 342 + 343 + static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, 344 + struct snd_ctl_elem_value *ucontrol) 345 + { 346 + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 347 + struct hdmi_spec *spec; 348 + int pin_idx; 349 + 350 + spec = codec->spec; 351 + pin_idx = kcontrol->private_value; 352 + 353 + memcpy(ucontrol->value.bytes.data, 354 + spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE); 355 + 356 + return 0; 357 + } 358 + 359 + static struct snd_kcontrol_new eld_bytes_ctl = { 360 + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 361 + .iface = SNDRV_CTL_ELEM_IFACE_PCM, 362 + .name = "ELD", 363 + .info = hdmi_eld_ctl_info, 364 + .get = hdmi_eld_ctl_get, 365 + }; 366 + 367 + static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx, 368 + int device) 369 + { 370 + struct snd_kcontrol *kctl; 371 + struct hdmi_spec *spec = codec->spec; 372 + int err; 373 + 374 + kctl = snd_ctl_new1(&eld_bytes_ctl, codec); 375 + if (!kctl) 376 + return -ENOMEM; 377 + kctl->private_value = pin_idx; 378 + kctl->id.device = device; 379 + 380 + err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl); 381 + if (err < 0) 382 + return err; 383 + 384 + return 0; 385 + } 386 + 327 387 #ifdef BE_PARANOID 328 388 static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, 329 389 int *packet_index, int *byte_index) ··· 1253 1193 if (err < 0) 1254 1194 return err; 1255 1195 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1196 + 1197 + /* add control for ELD Bytes */ 1198 + err = hdmi_create_eld_ctl(codec, 1199 + pin_idx, 1200 + spec->pcm_rec[pin_idx].device); 1201 + 1202 + if (err < 0) 1203 + return err; 1256 1204 } 1257 1205 1258 1206 return 0;