ALSA: hda - hdmi: Fix channel maps with less common speakers
authorAnssi Hannula <anssi.hannula@iki.fi>
Fri, 4 Oct 2013 23:25:42 +0000 (02:25 +0300)
committerTakashi Iwai <tiwai@suse.de>
Mon, 7 Oct 2013 10:48:15 +0000 (12:48 +0200)
For some speakers and slots the CEA slot <-> speaker assignment depends
on the used CEA Channel Allocation value.

Therefore the from_cea_slot() and to_cea_slot() helpers currently only
work correctly for the regular 7.1 speakers.

Fix them to work with all speakers, taking the re-ordered CA index as
input and adapting use sites accordingly.

This change allows manual channel mapping to actually work for all CEA
allocated speakers. Additionally, this fixes incorrect channel map
reporting in automatic channel mapping mode when an affected speaker
position is used (e.g. 6.1 map which contains an RC speaker).

Signed-off-by: Anssi Hannula <anssi.hannula@iki.fi>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_hdmi.c

index 8bf526ea8cf27919f0c3fd9fe35ffe3aa2247eee..dab2af762d94168af03cb571b3c218f3fe355869 100644 (file)
@@ -643,19 +643,27 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
 
 struct channel_map_table {
        unsigned char map;              /* ALSA API channel map position */
-       unsigned char cea_slot;         /* CEA slot value */
        int spk_mask;                   /* speaker position bit mask */
 };
 
 static struct channel_map_table map_tables[] = {
-       { SNDRV_CHMAP_FL,       0x00,   FL },
-       { SNDRV_CHMAP_FR,       0x01,   FR },
-       { SNDRV_CHMAP_RL,       0x04,   RL },
-       { SNDRV_CHMAP_RR,       0x05,   RR },
-       { SNDRV_CHMAP_LFE,      0x02,   LFE },
-       { SNDRV_CHMAP_FC,       0x03,   FC },
-       { SNDRV_CHMAP_RLC,      0x06,   RLC },
-       { SNDRV_CHMAP_RRC,      0x07,   RRC },
+       { SNDRV_CHMAP_FL,       FL },
+       { SNDRV_CHMAP_FR,       FR },
+       { SNDRV_CHMAP_RL,       RL },
+       { SNDRV_CHMAP_RR,       RR },
+       { SNDRV_CHMAP_LFE,      LFE },
+       { SNDRV_CHMAP_FC,       FC },
+       { SNDRV_CHMAP_RLC,      RLC },
+       { SNDRV_CHMAP_RRC,      RRC },
+       { SNDRV_CHMAP_RC,       RC },
+       { SNDRV_CHMAP_FLC,      FLC },
+       { SNDRV_CHMAP_FRC,      FRC },
+       { SNDRV_CHMAP_FLH,      FLH },
+       { SNDRV_CHMAP_FRH,      FRH },
+       { SNDRV_CHMAP_FLW,      FLW },
+       { SNDRV_CHMAP_FRW,      FRW },
+       { SNDRV_CHMAP_TC,       TC },
+       { SNDRV_CHMAP_FCH,      FCH },
        {} /* terminator */
 };
 
@@ -671,25 +679,19 @@ static int to_spk_mask(unsigned char c)
 }
 
 /* from ALSA API channel position to CEA slot */
-static int to_cea_slot(unsigned char c)
+static int to_cea_slot(int ordered_ca, unsigned char pos)
 {
-       struct channel_map_table *t = map_tables;
-       for (; t->map; t++) {
-               if (t->map == c)
-                       return t->cea_slot;
-       }
-       return -1;
-}
+       int mask = to_spk_mask(pos);
+       int i;
 
-/* from CEA slot to ALSA API channel position */
-static int from_cea_slot(unsigned char c)
-{
-       struct channel_map_table *t = map_tables;
-       for (; t->map; t++) {
-               if (t->cea_slot == c)
-                       return t->map;
+       if (mask) {
+               for (i = 0; i < 8; i++) {
+                       if (channel_allocations[ordered_ca].speakers[7 - i] == mask)
+                               return i;
+               }
        }
-       return 0;
+
+       return -1;
 }
 
 /* from speaker bit mask to ALSA API channel position */
@@ -703,6 +705,14 @@ static int spk_to_chmap(int spk)
        return 0;
 }
 
+/* from CEA slot to ALSA API channel position */
+static int from_cea_slot(int ordered_ca, unsigned char slot)
+{
+       int mask = channel_allocations[ordered_ca].speakers[7 - slot];
+
+       return spk_to_chmap(mask);
+}
+
 /* get the CA index corresponding to the given ALSA API channel map */
 static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
 {
@@ -729,14 +739,16 @@ static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
 /* set up the channel slots for the given ALSA API channel map */
 static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
                                             hda_nid_t pin_nid,
-                                            int chs, unsigned char *map)
+                                            int chs, unsigned char *map,
+                                            int ca)
 {
+       int ordered_ca = get_channel_allocation_order(ca);
        int alsa_pos, hdmi_slot;
        int assignments[8] = {[0 ... 7] = 0xf};
 
        for (alsa_pos = 0; alsa_pos < chs; alsa_pos++) {
 
-               hdmi_slot = to_cea_slot(map[alsa_pos]);
+               hdmi_slot = to_cea_slot(ordered_ca, map[alsa_pos]);
 
                if (hdmi_slot < 0)
                        continue; /* unassigned channel */
@@ -763,7 +775,7 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
        int ordered_ca = get_channel_allocation_order(ca);
        for (i = 0; i < 8; i++) {
                if (i < channel_allocations[ordered_ca].channels)
-                       map[i] = from_cea_slot(hdmi_channel_mapping[ca][i] & 0x0f);
+                       map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f);
                else
                        map[i] = 0;
        }
@@ -776,7 +788,7 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
 {
        if (!non_pcm && chmap_set) {
                hdmi_manual_setup_channel_mapping(codec, pin_nid,
-                                                 channels, map);
+                                                 channels, map, ca);
        } else {
                hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
                hdmi_setup_fake_chmap(map, ca);