|
@@ -625,13 +625,30 @@ static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
|
|
|
WARN_ON(count != channels);
|
|
|
}
|
|
|
|
|
|
+static int spk_mask_from_spk_alloc(int spk_alloc)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int spk_mask = eld_speaker_allocation_bits[0];
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
|
|
|
+ if (spk_alloc & (1 << i))
|
|
|
+ spk_mask |= eld_speaker_allocation_bits[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ return spk_mask;
|
|
|
+}
|
|
|
+
|
|
|
static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|
|
unsigned int size, unsigned int __user *tlv)
|
|
|
{
|
|
|
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
|
|
|
struct hdac_chmap *chmap = info->private_data;
|
|
|
+ int pcm_idx = kcontrol->private_value;
|
|
|
unsigned int __user *dst;
|
|
|
int chs, count = 0;
|
|
|
+ unsigned long max_chs;
|
|
|
+ int type;
|
|
|
+ int spk_alloc, spk_mask;
|
|
|
|
|
|
if (size < 8)
|
|
|
return -ENOMEM;
|
|
@@ -639,40 +656,59 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
|
|
return -EFAULT;
|
|
|
size -= 8;
|
|
|
dst = tlv + 2;
|
|
|
- for (chs = 2; chs <= chmap->channels_max; chs++) {
|
|
|
+
|
|
|
+ spk_alloc = chmap->ops.get_spk_alloc(chmap->hdac, pcm_idx);
|
|
|
+ spk_mask = spk_mask_from_spk_alloc(spk_alloc);
|
|
|
+
|
|
|
+ max_chs = hweight_long(spk_mask);
|
|
|
+
|
|
|
+ for (chs = 2; chs <= max_chs; chs++) {
|
|
|
int i;
|
|
|
struct hdac_cea_channel_speaker_allocation *cap;
|
|
|
|
|
|
cap = channel_allocations;
|
|
|
for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
|
|
|
int chs_bytes = chs * 4;
|
|
|
- int type = chmap->ops.chmap_cea_alloc_validate_get_type(
|
|
|
- chmap, cap, chs);
|
|
|
unsigned int tlv_chmap[8];
|
|
|
|
|
|
- if (type < 0)
|
|
|
+ if (cap->channels != chs)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!(cap->spk_mask == (spk_mask & cap->spk_mask)))
|
|
|
continue;
|
|
|
+
|
|
|
+ type = chmap->ops.chmap_cea_alloc_validate_get_type(
|
|
|
+ chmap, cap, chs);
|
|
|
+ if (type < 0)
|
|
|
+ return -ENODEV;
|
|
|
if (size < 8)
|
|
|
return -ENOMEM;
|
|
|
+
|
|
|
if (put_user(type, dst) ||
|
|
|
put_user(chs_bytes, dst + 1))
|
|
|
return -EFAULT;
|
|
|
+
|
|
|
dst += 2;
|
|
|
size -= 8;
|
|
|
count += 8;
|
|
|
+
|
|
|
if (size < chs_bytes)
|
|
|
return -ENOMEM;
|
|
|
+
|
|
|
size -= chs_bytes;
|
|
|
count += chs_bytes;
|
|
|
chmap->ops.cea_alloc_to_tlv_chmap(chmap, cap,
|
|
|
tlv_chmap, chs);
|
|
|
+
|
|
|
if (copy_to_user(dst, tlv_chmap, chs_bytes))
|
|
|
return -EFAULT;
|
|
|
dst += chs;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
if (put_user(count, tlv + 1))
|
|
|
return -EFAULT;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|