aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>2011-09-30 17:35:41 -0400
committerTakashi Iwai <tiwai@suse.de>2011-10-03 09:48:12 -0400
commit14bc52b8feaae6cbc88934399f418125ac176399 (patch)
treee43a68246b931ab6001f9977886918145448b19d /sound/pci
parentef940b0403d4ae133c548b01fe64c74fa8a2f0b1 (diff)
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>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_eld.c13
-rw-r--r--sound/pci/hda/hda_local.h2
-rw-r--r--sound/pci/hda/patch_hdmi.c68
3 files changed, 78 insertions, 5 deletions
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index c34f730f4815..f1c621d2f8e8 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -318,6 +318,11 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
318 int size; 318 int size;
319 unsigned char *buf; 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 if (!eld->eld_valid) 326 if (!eld->eld_valid)
322 return -ENOENT; 327 return -ENOENT;
323 328
@@ -327,14 +332,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
327 snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); 332 snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n");
328 size = 128; 333 size = 128;
329 } 334 }
330 if (size < ELD_FIXED_BYTES || size > PAGE_SIZE) { 335 if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
331 snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); 336 snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size);
332 return -ERANGE; 337 return -ERANGE;
333 } 338 }
334 339
335 buf = kmalloc(size, GFP_KERNEL); 340 /* set ELD buffer */
336 if (!buf) 341 buf = eld->eld_buffer;
337 return -ENOMEM;
338 342
339 for (i = 0; i < size; i++) { 343 for (i = 0; i < size; i++) {
340 unsigned int val = hdmi_get_eld_data(codec, nid, i); 344 unsigned int val = hdmi_get_eld_data(codec, nid, i);
@@ -356,7 +360,6 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
356 ret = hdmi_update_eld(eld, buf, size); 360 ret = hdmi_update_eld(eld, buf, size);
357 361
358error: 362error:
359 kfree(buf);
360 return ret; 363 return ret;
361} 364}
362 365
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index aaefa7c81e68..04d730fffee2 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -621,6 +621,7 @@ struct cea_sad {
621}; 621};
622 622
623#define ELD_FIXED_BYTES 20 623#define ELD_FIXED_BYTES 20
624#define ELD_MAX_SIZE 256
624#define ELD_MAX_MNL 16 625#define ELD_MAX_MNL 16
625#define ELD_MAX_SAD 16 626#define ELD_MAX_SAD 16
626 627
@@ -645,6 +646,7 @@ struct hdmi_eld {
645 int spk_alloc; 646 int spk_alloc;
646 int sad_count; 647 int sad_count;
647 struct cea_sad sad[ELD_MAX_SAD]; 648 struct cea_sad sad[ELD_MAX_SAD];
649 char eld_buffer[ELD_MAX_SIZE];
648#ifdef CONFIG_PROC_FS 650#ifdef CONFIG_PROC_FS
649 struct snd_info_entry *proc_entry; 651 struct snd_info_entry *proc_entry;
650#endif 652#endif
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 3f1f6ac8e643..342540128fb8 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -324,6 +324,66 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
324 return -EINVAL; 324 return -EINVAL;
325} 325}
326 326
327static 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
343static 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
359static 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
367static 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#ifdef BE_PARANOID 387#ifdef BE_PARANOID
328static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, 388static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
329 int *packet_index, int *byte_index) 389 int *packet_index, int *byte_index)
@@ -1193,6 +1253,14 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
1193 if (err < 0) 1253 if (err < 0)
1194 return err; 1254 return err;
1195 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1255 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1256
1257 /* add control for ELD Bytes */
1258 err = hdmi_create_eld_ctl(codec,
1259 pin_idx,
1260 spec->pcm_rec[pin_idx].device);
1261
1262 if (err < 0)
1263 return err;
1196 } 1264 }
1197 1265
1198 return 0; 1266 return 0;