summaryrefslogtreecommitdiffstats
path: root/sound/hda
diff options
context:
space:
mode:
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>2016-04-04 09:53:54 -0400
committerTakashi Iwai <tiwai@suse.de>2016-04-04 10:04:24 -0400
commit44fde3b89ba1e154b3cec7d711703fff53852983 (patch)
tree5798bfdde03fa87a7b51a1ef10cfe3ea8415040b /sound/hda
parenta99e31512aa435e8391ba5f5e64abeac9c5f2f32 (diff)
ALSA: hda - Update chmap tlv to report sink's capability
The existing TLV callback implementation copies all of the cea_channel_speaker_allocation map table to the TLV container irrespective of what is reported by sink. This is of little use to the userspace application. With this patch, it parses the spk_alloc block as queried from the ELD, and copies only the corresponding mapping channel allocation entries from the cea channel speaker allocation table. Thus the user can parse the TLV container to identify sink's capability and set the channel map accordingly. It shouldn't impact the behavior in AMD chipset, as this makes use of already parsed spk alloc block to calculate the channel map. Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/hda')
-rw-r--r--sound/hda/hdmi_chmap.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c
index d7ec86263828..c6c75e7e0981 100644
--- a/sound/hda/hdmi_chmap.c
+++ b/sound/hda/hdmi_chmap.c
@@ -625,13 +625,30 @@ static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
625 WARN_ON(count != channels); 625 WARN_ON(count != channels);
626} 626}
627 627
628static int spk_mask_from_spk_alloc(int spk_alloc)
629{
630 int i;
631 int spk_mask = eld_speaker_allocation_bits[0];
632
633 for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
634 if (spk_alloc & (1 << i))
635 spk_mask |= eld_speaker_allocation_bits[i];
636 }
637
638 return spk_mask;
639}
640
628static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, 641static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
629 unsigned int size, unsigned int __user *tlv) 642 unsigned int size, unsigned int __user *tlv)
630{ 643{
631 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); 644 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
632 struct hdac_chmap *chmap = info->private_data; 645 struct hdac_chmap *chmap = info->private_data;
646 int pcm_idx = kcontrol->private_value;
633 unsigned int __user *dst; 647 unsigned int __user *dst;
634 int chs, count = 0; 648 int chs, count = 0;
649 unsigned long max_chs;
650 int type;
651 int spk_alloc, spk_mask;
635 652
636 if (size < 8) 653 if (size < 8)
637 return -ENOMEM; 654 return -ENOMEM;
@@ -639,40 +656,59 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
639 return -EFAULT; 656 return -EFAULT;
640 size -= 8; 657 size -= 8;
641 dst = tlv + 2; 658 dst = tlv + 2;
642 for (chs = 2; chs <= chmap->channels_max; chs++) { 659
660 spk_alloc = chmap->ops.get_spk_alloc(chmap->hdac, pcm_idx);
661 spk_mask = spk_mask_from_spk_alloc(spk_alloc);
662
663 max_chs = hweight_long(spk_mask);
664
665 for (chs = 2; chs <= max_chs; chs++) {
643 int i; 666 int i;
644 struct hdac_cea_channel_speaker_allocation *cap; 667 struct hdac_cea_channel_speaker_allocation *cap;
645 668
646 cap = channel_allocations; 669 cap = channel_allocations;
647 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) { 670 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
648 int chs_bytes = chs * 4; 671 int chs_bytes = chs * 4;
649 int type = chmap->ops.chmap_cea_alloc_validate_get_type(
650 chmap, cap, chs);
651 unsigned int tlv_chmap[8]; 672 unsigned int tlv_chmap[8];
652 673
653 if (type < 0) 674 if (cap->channels != chs)
675 continue;
676
677 if (!(cap->spk_mask == (spk_mask & cap->spk_mask)))
654 continue; 678 continue;
679
680 type = chmap->ops.chmap_cea_alloc_validate_get_type(
681 chmap, cap, chs);
682 if (type < 0)
683 return -ENODEV;
655 if (size < 8) 684 if (size < 8)
656 return -ENOMEM; 685 return -ENOMEM;
686
657 if (put_user(type, dst) || 687 if (put_user(type, dst) ||
658 put_user(chs_bytes, dst + 1)) 688 put_user(chs_bytes, dst + 1))
659 return -EFAULT; 689 return -EFAULT;
690
660 dst += 2; 691 dst += 2;
661 size -= 8; 692 size -= 8;
662 count += 8; 693 count += 8;
694
663 if (size < chs_bytes) 695 if (size < chs_bytes)
664 return -ENOMEM; 696 return -ENOMEM;
697
665 size -= chs_bytes; 698 size -= chs_bytes;
666 count += chs_bytes; 699 count += chs_bytes;
667 chmap->ops.cea_alloc_to_tlv_chmap(chmap, cap, 700 chmap->ops.cea_alloc_to_tlv_chmap(chmap, cap,
668 tlv_chmap, chs); 701 tlv_chmap, chs);
702
669 if (copy_to_user(dst, tlv_chmap, chs_bytes)) 703 if (copy_to_user(dst, tlv_chmap, chs_bytes))
670 return -EFAULT; 704 return -EFAULT;
671 dst += chs; 705 dst += chs;
672 } 706 }
673 } 707 }
708
674 if (put_user(count, tlv + 1)) 709 if (put_user(count, tlv + 1))
675 return -EFAULT; 710 return -EFAULT;
711
676 return 0; 712 return 0;
677} 713}
678 714