linux/sound/hda/hdmi_chmap.c
<<
>>
Prefs
   1/*
   2 * HDMI Channel map support helpers
   3 */
   4
   5#include <linux/module.h>
   6#include <sound/control.h>
   7#include <sound/tlv.h>
   8#include <sound/hda_chmap.h>
   9
  10/*
  11 * CEA speaker placement:
  12 *
  13 *        FLH       FCH        FRH
  14 *  FLW    FL  FLC   FC   FRC   FR   FRW
  15 *
  16 *                                  LFE
  17 *                     TC
  18 *
  19 *          RL  RLC   RC   RRC   RR
  20 *
  21 * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to
  22 * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC.
  23 */
  24enum cea_speaker_placement {
  25        FL  = (1 <<  0),        /* Front Left           */
  26        FC  = (1 <<  1),        /* Front Center         */
  27        FR  = (1 <<  2),        /* Front Right          */
  28        FLC = (1 <<  3),        /* Front Left Center    */
  29        FRC = (1 <<  4),        /* Front Right Center   */
  30        RL  = (1 <<  5),        /* Rear Left            */
  31        RC  = (1 <<  6),        /* Rear Center          */
  32        RR  = (1 <<  7),        /* Rear Right           */
  33        RLC = (1 <<  8),        /* Rear Left Center     */
  34        RRC = (1 <<  9),        /* Rear Right Center    */
  35        LFE = (1 << 10),        /* Low Frequency Effect */
  36        FLW = (1 << 11),        /* Front Left Wide      */
  37        FRW = (1 << 12),        /* Front Right Wide     */
  38        FLH = (1 << 13),        /* Front Left High      */
  39        FCH = (1 << 14),        /* Front Center High    */
  40        FRH = (1 << 15),        /* Front Right High     */
  41        TC  = (1 << 16),        /* Top Center           */
  42};
  43
  44static const char * const cea_speaker_allocation_names[] = {
  45        /*  0 */ "FL/FR",
  46        /*  1 */ "LFE",
  47        /*  2 */ "FC",
  48        /*  3 */ "RL/RR",
  49        /*  4 */ "RC",
  50        /*  5 */ "FLC/FRC",
  51        /*  6 */ "RLC/RRC",
  52        /*  7 */ "FLW/FRW",
  53        /*  8 */ "FLH/FRH",
  54        /*  9 */ "TC",
  55        /* 10 */ "FCH",
  56};
  57
  58/*
  59 * ELD SA bits in the CEA Speaker Allocation data block
  60 */
  61static int eld_speaker_allocation_bits[] = {
  62        [0] = FL | FR,
  63        [1] = LFE,
  64        [2] = FC,
  65        [3] = RL | RR,
  66        [4] = RC,
  67        [5] = FLC | FRC,
  68        [6] = RLC | RRC,
  69        /* the following are not defined in ELD yet */
  70        [7] = FLW | FRW,
  71        [8] = FLH | FRH,
  72        [9] = TC,
  73        [10] = FCH,
  74};
  75
  76/*
  77 * ALSA sequence is:
  78 *
  79 *       surround40   surround41   surround50   surround51   surround71
  80 * ch0   front left   =            =            =            =
  81 * ch1   front right  =            =            =            =
  82 * ch2   rear left    =            =            =            =
  83 * ch3   rear right   =            =            =            =
  84 * ch4                LFE          center       center       center
  85 * ch5                                          LFE          LFE
  86 * ch6                                                       side left
  87 * ch7                                                       side right
  88 *
  89 * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR}
  90 */
  91static int hdmi_channel_mapping[0x32][8] = {
  92        /* stereo */
  93        [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
  94        /* 2.1 */
  95        [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
  96        /* Dolby Surround */
  97        [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 },
  98        /* surround40 */
  99        [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 },
 100        /* 4ch */
 101        [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 },
 102        /* surround41 */
 103        [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 },
 104        /* surround50 */
 105        [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 },
 106        /* surround51 */
 107        [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 },
 108        /* 7.1 */
 109        [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 },
 110};
 111
 112/*
 113 * This is an ordered list!
 114 *
 115 * The preceding ones have better chances to be selected by
 116 * hdmi_channel_allocation().
 117 */
 118static struct hdac_cea_channel_speaker_allocation channel_allocations[] = {
 119/*                        channel:   7     6    5    4    3     2    1    0  */
 120{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
 121                                 /* 2.1 */
 122{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
 123                                 /* Dolby Surround */
 124{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
 125                                 /* surround40 */
 126{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
 127                                 /* surround41 */
 128{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
 129                                 /* surround50 */
 130{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
 131                                 /* surround51 */
 132{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
 133                                 /* 6.1 */
 134{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
 135                                 /* surround71 */
 136{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
 137
 138{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
 139{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
 140{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
 141{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
 142{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
 143{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
 144{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
 145{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
 146{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
 147{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
 148{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
 149{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
 150{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
 151{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
 152{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
 153{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
 154{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
 155{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
 156{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
 157{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
 158{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
 159{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
 160{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
 161{ .ca_index = 0x20,  .speakers = {   0,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
 162{ .ca_index = 0x21,  .speakers = {   0,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
 163{ .ca_index = 0x22,  .speakers = {  TC,    0,  RR,  RL,  FC,    0,  FR,  FL } },
 164{ .ca_index = 0x23,  .speakers = {  TC,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
 165{ .ca_index = 0x24,  .speakers = { FRH,  FLH,  RR,  RL,   0,    0,  FR,  FL } },
 166{ .ca_index = 0x25,  .speakers = { FRH,  FLH,  RR,  RL,   0,  LFE,  FR,  FL } },
 167{ .ca_index = 0x26,  .speakers = { FRW,  FLW,  RR,  RL,   0,    0,  FR,  FL } },
 168{ .ca_index = 0x27,  .speakers = { FRW,  FLW,  RR,  RL,   0,  LFE,  FR,  FL } },
 169{ .ca_index = 0x28,  .speakers = {  TC,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
 170{ .ca_index = 0x29,  .speakers = {  TC,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
 171{ .ca_index = 0x2a,  .speakers = { FCH,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
 172{ .ca_index = 0x2b,  .speakers = { FCH,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
 173{ .ca_index = 0x2c,  .speakers = {  TC,  FCH,  RR,  RL,  FC,    0,  FR,  FL } },
 174{ .ca_index = 0x2d,  .speakers = {  TC,  FCH,  RR,  RL,  FC,  LFE,  FR,  FL } },
 175{ .ca_index = 0x2e,  .speakers = { FRH,  FLH,  RR,  RL,  FC,    0,  FR,  FL } },
 176{ .ca_index = 0x2f,  .speakers = { FRH,  FLH,  RR,  RL,  FC,  LFE,  FR,  FL } },
 177{ .ca_index = 0x30,  .speakers = { FRW,  FLW,  RR,  RL,  FC,    0,  FR,  FL } },
 178{ .ca_index = 0x31,  .speakers = { FRW,  FLW,  RR,  RL,  FC,  LFE,  FR,  FL } },
 179};
 180
 181static int hdmi_pin_set_slot_channel(struct hdac_device *codec,
 182                hda_nid_t pin_nid, int asp_slot, int channel)
 183{
 184        return snd_hdac_codec_write(codec, pin_nid, 0,
 185                                AC_VERB_SET_HDMI_CHAN_SLOT,
 186                                (channel << 4) | asp_slot);
 187}
 188
 189static int hdmi_pin_get_slot_channel(struct hdac_device *codec,
 190                        hda_nid_t pin_nid, int asp_slot)
 191{
 192        return (snd_hdac_codec_read(codec, pin_nid, 0,
 193                                   AC_VERB_GET_HDMI_CHAN_SLOT,
 194                                   asp_slot) & 0xf0) >> 4;
 195}
 196
 197static int hdmi_get_channel_count(struct hdac_device *codec, hda_nid_t cvt_nid)
 198{
 199        return 1 + snd_hdac_codec_read(codec, cvt_nid, 0,
 200                                        AC_VERB_GET_CVT_CHAN_COUNT, 0);
 201}
 202
 203static void hdmi_set_channel_count(struct hdac_device *codec,
 204                                   hda_nid_t cvt_nid, int chs)
 205{
 206        if (chs != hdmi_get_channel_count(codec, cvt_nid))
 207                snd_hdac_codec_write(codec, cvt_nid, 0,
 208                                    AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
 209}
 210
 211/*
 212 * Channel mapping routines
 213 */
 214
 215/*
 216 * Compute derived values in channel_allocations[].
 217 */
 218static void init_channel_allocations(void)
 219{
 220        int i, j;
 221        struct hdac_cea_channel_speaker_allocation *p;
 222
 223        for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
 224                p = channel_allocations + i;
 225                p->channels = 0;
 226                p->spk_mask = 0;
 227                for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
 228                        if (p->speakers[j]) {
 229                                p->channels++;
 230                                p->spk_mask |= p->speakers[j];
 231                        }
 232        }
 233}
 234
 235static int get_channel_allocation_order(int ca)
 236{
 237        int i;
 238
 239        for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
 240                if (channel_allocations[i].ca_index == ca)
 241                        break;
 242        }
 243        return i;
 244}
 245
 246void snd_hdac_print_channel_allocation(int spk_alloc, char *buf, int buflen)
 247{
 248        int i, j;
 249
 250        for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
 251                if (spk_alloc & (1 << i))
 252                        j += snprintf(buf + j, buflen - j,  " %s",
 253                                        cea_speaker_allocation_names[i]);
 254        }
 255        buf[j] = '\0';  /* necessary when j == 0 */
 256}
 257EXPORT_SYMBOL_GPL(snd_hdac_print_channel_allocation);
 258
 259/*
 260 * The transformation takes two steps:
 261 *
 262 *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
 263 *            spk_mask => (channel_allocations[])         => ai->CA
 264 *
 265 * TODO: it could select the wrong CA from multiple candidates.
 266*/
 267static int hdmi_channel_allocation_spk_alloc_blk(struct hdac_device *codec,
 268                                   int spk_alloc, int channels)
 269{
 270        int i;
 271        int ca = 0;
 272        int spk_mask = 0;
 273        char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
 274
 275        /*
 276         * CA defaults to 0 for basic stereo audio
 277         */
 278        if (channels <= 2)
 279                return 0;
 280
 281        /*
 282         * expand ELD's speaker allocation mask
 283         *
 284         * ELD tells the speaker mask in a compact(paired) form,
 285         * expand ELD's notions to match the ones used by Audio InfoFrame.
 286         */
 287        for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
 288                if (spk_alloc & (1 << i))
 289                        spk_mask |= eld_speaker_allocation_bits[i];
 290        }
 291
 292        /* search for the first working match in the CA table */
 293        for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
 294                if (channels == channel_allocations[i].channels &&
 295                    (spk_mask & channel_allocations[i].spk_mask) ==
 296                                channel_allocations[i].spk_mask) {
 297                        ca = channel_allocations[i].ca_index;
 298                        break;
 299                }
 300        }
 301
 302        if (!ca) {
 303                /*
 304                 * if there was no match, select the regular ALSA channel
 305                 * allocation with the matching number of channels
 306                 */
 307                for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
 308                        if (channels == channel_allocations[i].channels) {
 309                                ca = channel_allocations[i].ca_index;
 310                                break;
 311                        }
 312                }
 313        }
 314
 315        snd_hdac_print_channel_allocation(spk_alloc, buf, sizeof(buf));
 316        dev_dbg(&codec->dev, "HDMI: select CA 0x%x for %d-channel allocation: %s\n",
 317                    ca, channels, buf);
 318
 319        return ca;
 320}
 321
 322static void hdmi_debug_channel_mapping(struct hdac_chmap *chmap,
 323                                       hda_nid_t pin_nid)
 324{
 325#ifdef CONFIG_SND_DEBUG_VERBOSE
 326        int i;
 327        int channel;
 328
 329        for (i = 0; i < 8; i++) {
 330                channel = chmap->ops.pin_get_slot_channel(
 331                                chmap->hdac, pin_nid, i);
 332                dev_dbg(&chmap->hdac->dev, "HDMI: ASP channel %d => slot %d\n",
 333                                                channel, i);
 334        }
 335#endif
 336}
 337
 338static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap,
 339                                       hda_nid_t pin_nid,
 340                                       bool non_pcm,
 341                                       int ca)
 342{
 343        struct hdac_cea_channel_speaker_allocation *ch_alloc;
 344        int i;
 345        int err;
 346        int order;
 347        int non_pcm_mapping[8];
 348
 349        order = get_channel_allocation_order(ca);
 350        ch_alloc = &channel_allocations[order];
 351
 352        if (hdmi_channel_mapping[ca][1] == 0) {
 353                int hdmi_slot = 0;
 354                /* fill actual channel mappings in ALSA channel (i) order */
 355                for (i = 0; i < ch_alloc->channels; i++) {
 356                        while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8))
 357                                hdmi_slot++; /* skip zero slots */
 358
 359                        hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++;
 360                }
 361                /* fill the rest of the slots with ALSA channel 0xf */
 362                for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++)
 363                        if (!ch_alloc->speakers[7 - hdmi_slot])
 364                                hdmi_channel_mapping[ca][i++] = (0xf << 4) | hdmi_slot;
 365        }
 366
 367        if (non_pcm) {
 368                for (i = 0; i < ch_alloc->channels; i++)
 369                        non_pcm_mapping[i] = (i << 4) | i;
 370                for (; i < 8; i++)
 371                        non_pcm_mapping[i] = (0xf << 4) | i;
 372        }
 373
 374        for (i = 0; i < 8; i++) {
 375                int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i];
 376                int hdmi_slot = slotsetup & 0x0f;
 377                int channel = (slotsetup & 0xf0) >> 4;
 378
 379                err = chmap->ops.pin_set_slot_channel(chmap->hdac,
 380                                pin_nid, hdmi_slot, channel);
 381                if (err) {
 382                        dev_dbg(&chmap->hdac->dev, "HDMI: channel mapping failed\n");
 383                        break;
 384                }
 385        }
 386}
 387
 388struct channel_map_table {
 389        unsigned char map;              /* ALSA API channel map position */
 390        int spk_mask;                   /* speaker position bit mask */
 391};
 392
 393static struct channel_map_table map_tables[] = {
 394        { SNDRV_CHMAP_FL,       FL },
 395        { SNDRV_CHMAP_FR,       FR },
 396        { SNDRV_CHMAP_RL,       RL },
 397        { SNDRV_CHMAP_RR,       RR },
 398        { SNDRV_CHMAP_LFE,      LFE },
 399        { SNDRV_CHMAP_FC,       FC },
 400        { SNDRV_CHMAP_RLC,      RLC },
 401        { SNDRV_CHMAP_RRC,      RRC },
 402        { SNDRV_CHMAP_RC,       RC },
 403        { SNDRV_CHMAP_FLC,      FLC },
 404        { SNDRV_CHMAP_FRC,      FRC },
 405        { SNDRV_CHMAP_TFL,      FLH },
 406        { SNDRV_CHMAP_TFR,      FRH },
 407        { SNDRV_CHMAP_FLW,      FLW },
 408        { SNDRV_CHMAP_FRW,      FRW },
 409        { SNDRV_CHMAP_TC,       TC },
 410        { SNDRV_CHMAP_TFC,      FCH },
 411        {} /* terminator */
 412};
 413
 414/* from ALSA API channel position to speaker bit mask */
 415int snd_hdac_chmap_to_spk_mask(unsigned char c)
 416{
 417        struct channel_map_table *t = map_tables;
 418
 419        for (; t->map; t++) {
 420                if (t->map == c)
 421                        return t->spk_mask;
 422        }
 423        return 0;
 424}
 425EXPORT_SYMBOL_GPL(snd_hdac_chmap_to_spk_mask);
 426
 427/* from ALSA API channel position to CEA slot */
 428static int to_cea_slot(int ordered_ca, unsigned char pos)
 429{
 430        int mask = snd_hdac_chmap_to_spk_mask(pos);
 431        int i;
 432
 433        if (mask) {
 434                for (i = 0; i < 8; i++) {
 435                        if (channel_allocations[ordered_ca].speakers[7 - i] == mask)
 436                                return i;
 437                }
 438        }
 439
 440        return -1;
 441}
 442
 443/* from speaker bit mask to ALSA API channel position */
 444int snd_hdac_spk_to_chmap(int spk)
 445{
 446        struct channel_map_table *t = map_tables;
 447
 448        for (; t->map; t++) {
 449                if (t->spk_mask == spk)
 450                        return t->map;
 451        }
 452        return 0;
 453}
 454EXPORT_SYMBOL_GPL(snd_hdac_spk_to_chmap);
 455
 456/* from CEA slot to ALSA API channel position */
 457static int from_cea_slot(int ordered_ca, unsigned char slot)
 458{
 459        int mask = channel_allocations[ordered_ca].speakers[7 - slot];
 460
 461        return snd_hdac_spk_to_chmap(mask);
 462}
 463
 464/* get the CA index corresponding to the given ALSA API channel map */
 465static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
 466{
 467        int i, spks = 0, spk_mask = 0;
 468
 469        for (i = 0; i < chs; i++) {
 470                int mask = snd_hdac_chmap_to_spk_mask(map[i]);
 471
 472                if (mask) {
 473                        spk_mask |= mask;
 474                        spks++;
 475                }
 476        }
 477
 478        for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
 479                if ((chs == channel_allocations[i].channels ||
 480                     spks == channel_allocations[i].channels) &&
 481                    (spk_mask & channel_allocations[i].spk_mask) ==
 482                                channel_allocations[i].spk_mask)
 483                        return channel_allocations[i].ca_index;
 484        }
 485        return -1;
 486}
 487
 488/* set up the channel slots for the given ALSA API channel map */
 489static int hdmi_manual_setup_channel_mapping(struct hdac_chmap *chmap,
 490                                             hda_nid_t pin_nid,
 491                                             int chs, unsigned char *map,
 492                                             int ca)
 493{
 494        int ordered_ca = get_channel_allocation_order(ca);
 495        int alsa_pos, hdmi_slot;
 496        int assignments[8] = {[0 ... 7] = 0xf};
 497
 498        for (alsa_pos = 0; alsa_pos < chs; alsa_pos++) {
 499
 500                hdmi_slot = to_cea_slot(ordered_ca, map[alsa_pos]);
 501
 502                if (hdmi_slot < 0)
 503                        continue; /* unassigned channel */
 504
 505                assignments[hdmi_slot] = alsa_pos;
 506        }
 507
 508        for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) {
 509                int err;
 510
 511                err = chmap->ops.pin_set_slot_channel(chmap->hdac,
 512                                pin_nid, hdmi_slot, assignments[hdmi_slot]);
 513                if (err)
 514                        return -EINVAL;
 515        }
 516        return 0;
 517}
 518
 519/* store ALSA API channel map from the current default map */
 520static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
 521{
 522        int i;
 523        int ordered_ca = get_channel_allocation_order(ca);
 524
 525        for (i = 0; i < 8; i++) {
 526                if (i < channel_allocations[ordered_ca].channels)
 527                        map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f);
 528                else
 529                        map[i] = 0;
 530        }
 531}
 532
 533void snd_hdac_setup_channel_mapping(struct hdac_chmap *chmap,
 534                                       hda_nid_t pin_nid, bool non_pcm, int ca,
 535                                       int channels, unsigned char *map,
 536                                       bool chmap_set)
 537{
 538        if (!non_pcm && chmap_set) {
 539                hdmi_manual_setup_channel_mapping(chmap, pin_nid,
 540                                                  channels, map, ca);
 541        } else {
 542                hdmi_std_setup_channel_mapping(chmap, pin_nid, non_pcm, ca);
 543                hdmi_setup_fake_chmap(map, ca);
 544        }
 545
 546        hdmi_debug_channel_mapping(chmap, pin_nid);
 547}
 548EXPORT_SYMBOL_GPL(snd_hdac_setup_channel_mapping);
 549
 550int snd_hdac_get_active_channels(int ca)
 551{
 552        int ordered_ca = get_channel_allocation_order(ca);
 553
 554        return channel_allocations[ordered_ca].channels;
 555}
 556EXPORT_SYMBOL_GPL(snd_hdac_get_active_channels);
 557
 558struct hdac_cea_channel_speaker_allocation *snd_hdac_get_ch_alloc_from_ca(int ca)
 559{
 560        return &channel_allocations[get_channel_allocation_order(ca)];
 561}
 562EXPORT_SYMBOL_GPL(snd_hdac_get_ch_alloc_from_ca);
 563
 564int snd_hdac_channel_allocation(struct hdac_device *hdac, int spk_alloc,
 565                int channels, bool chmap_set, bool non_pcm, unsigned char *map)
 566{
 567        int ca;
 568
 569        if (!non_pcm && chmap_set)
 570                ca = hdmi_manual_channel_allocation(channels, map);
 571        else
 572                ca = hdmi_channel_allocation_spk_alloc_blk(hdac,
 573                                        spk_alloc, channels);
 574
 575        if (ca < 0)
 576                ca = 0;
 577
 578        return ca;
 579}
 580EXPORT_SYMBOL_GPL(snd_hdac_channel_allocation);
 581
 582/*
 583 * ALSA API channel-map control callbacks
 584 */
 585static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
 586                               struct snd_ctl_elem_info *uinfo)
 587{
 588        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
 589        struct hdac_chmap *chmap = info->private_data;
 590
 591        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 592        uinfo->count = chmap->channels_max;
 593        uinfo->value.integer.min = 0;
 594        uinfo->value.integer.max = SNDRV_CHMAP_LAST;
 595        return 0;
 596}
 597
 598static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
 599                struct hdac_cea_channel_speaker_allocation *cap, int channels)
 600{
 601        /* If the speaker allocation matches the channel count, it is OK.*/
 602        if (cap->channels != channels)
 603                return -1;
 604
 605        /* all channels are remappable freely */
 606        return SNDRV_CTL_TLVT_CHMAP_VAR;
 607}
 608
 609static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
 610                struct hdac_cea_channel_speaker_allocation *cap,
 611                unsigned int *chmap, int channels)
 612{
 613        int count = 0;
 614        int c;
 615
 616        for (c = 7; c >= 0; c--) {
 617                int spk = cap->speakers[c];
 618
 619                if (!spk)
 620                        continue;
 621
 622                chmap[count++] = snd_hdac_spk_to_chmap(spk);
 623        }
 624
 625        WARN_ON(count != channels);
 626}
 627
 628static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
 629                              unsigned int size, unsigned int __user *tlv)
 630{
 631        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
 632        struct hdac_chmap *chmap = info->private_data;
 633        unsigned int __user *dst;
 634        int chs, count = 0;
 635
 636        if (size < 8)
 637                return -ENOMEM;
 638        if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
 639                return -EFAULT;
 640        size -= 8;
 641        dst = tlv + 2;
 642        for (chs = 2; chs <= chmap->channels_max; chs++) {
 643                int i;
 644                struct hdac_cea_channel_speaker_allocation *cap;
 645
 646                cap = channel_allocations;
 647                for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
 648                        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];
 652
 653                        if (type < 0)
 654                                continue;
 655                        if (size < 8)
 656                                return -ENOMEM;
 657                        if (put_user(type, dst) ||
 658                            put_user(chs_bytes, dst + 1))
 659                                return -EFAULT;
 660                        dst += 2;
 661                        size -= 8;
 662                        count += 8;
 663                        if (size < chs_bytes)
 664                                return -ENOMEM;
 665                        size -= chs_bytes;
 666                        count += chs_bytes;
 667                        chmap->ops.cea_alloc_to_tlv_chmap(chmap, cap,
 668                                                tlv_chmap, chs);
 669                        if (copy_to_user(dst, tlv_chmap, chs_bytes))
 670                                return -EFAULT;
 671                        dst += chs;
 672                }
 673        }
 674        if (put_user(count, tlv + 1))
 675                return -EFAULT;
 676        return 0;
 677}
 678
 679static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
 680                              struct snd_ctl_elem_value *ucontrol)
 681{
 682        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
 683        struct hdac_chmap *chmap = info->private_data;
 684        int pcm_idx = kcontrol->private_value;
 685        unsigned char pcm_chmap[8];
 686        int i;
 687
 688        memset(pcm_chmap, 0, sizeof(pcm_chmap));
 689        chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap);
 690
 691        for (i = 0; i < sizeof(chmap); i++)
 692                ucontrol->value.integer.value[i] = pcm_chmap[i];
 693
 694        return 0;
 695}
 696
 697static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
 698                              struct snd_ctl_elem_value *ucontrol)
 699{
 700        struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
 701        struct hdac_chmap *hchmap = info->private_data;
 702        int pcm_idx = kcontrol->private_value;
 703        unsigned int ctl_idx;
 704        struct snd_pcm_substream *substream;
 705        unsigned char chmap[8], per_pin_chmap[8];
 706        int i, err, ca, prepared = 0;
 707
 708        /* No monitor is connected in dyn_pcm_assign.
 709         * It's invalid to setup the chmap
 710         */
 711        if (!hchmap->ops.is_pcm_attached(hchmap->hdac, pcm_idx))
 712                return 0;
 713
 714        ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 715        substream = snd_pcm_chmap_substream(info, ctl_idx);
 716        if (!substream || !substream->runtime)
 717                return 0; /* just for avoiding error from alsactl restore */
 718        switch (substream->runtime->status->state) {
 719        case SNDRV_PCM_STATE_OPEN:
 720        case SNDRV_PCM_STATE_SETUP:
 721                break;
 722        case SNDRV_PCM_STATE_PREPARED:
 723                prepared = 1;
 724                break;
 725        default:
 726                return -EBUSY;
 727        }
 728        memset(chmap, 0, sizeof(chmap));
 729        for (i = 0; i < ARRAY_SIZE(chmap); i++)
 730                chmap[i] = ucontrol->value.integer.value[i];
 731
 732        hchmap->ops.get_chmap(hchmap->hdac, pcm_idx, per_pin_chmap);
 733        if (!memcmp(chmap, per_pin_chmap, sizeof(chmap)))
 734                return 0;
 735        ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
 736        if (ca < 0)
 737                return -EINVAL;
 738        if (hchmap->ops.chmap_validate) {
 739                err = hchmap->ops.chmap_validate(hchmap, ca,
 740                                ARRAY_SIZE(chmap), chmap);
 741                if (err)
 742                        return err;
 743        }
 744
 745        hchmap->ops.set_chmap(hchmap->hdac, pcm_idx, chmap, prepared);
 746
 747        return 0;
 748}
 749
 750static const struct hdac_chmap_ops chmap_ops = {
 751        .chmap_cea_alloc_validate_get_type      = hdmi_chmap_cea_alloc_validate_get_type,
 752        .cea_alloc_to_tlv_chmap                 = hdmi_cea_alloc_to_tlv_chmap,
 753        .pin_get_slot_channel                   = hdmi_pin_get_slot_channel,
 754        .pin_set_slot_channel                   = hdmi_pin_set_slot_channel,
 755        .set_channel_count                      = hdmi_set_channel_count,
 756};
 757
 758void snd_hdac_register_chmap_ops(struct hdac_device *hdac,
 759                                struct hdac_chmap *chmap)
 760{
 761        chmap->ops = chmap_ops;
 762        chmap->hdac = hdac;
 763        init_channel_allocations();
 764}
 765EXPORT_SYMBOL_GPL(snd_hdac_register_chmap_ops);
 766
 767int snd_hdac_add_chmap_ctls(struct snd_pcm *pcm, int pcm_idx,
 768                                struct hdac_chmap *hchmap)
 769{
 770        struct snd_pcm_chmap *chmap;
 771        struct snd_kcontrol *kctl;
 772        int err, i;
 773
 774        err = snd_pcm_add_chmap_ctls(pcm,
 775                                     SNDRV_PCM_STREAM_PLAYBACK,
 776                                     NULL, 0, pcm_idx, &chmap);
 777        if (err < 0)
 778                return err;
 779        /* override handlers */
 780        chmap->private_data = hchmap;
 781        kctl = chmap->kctl;
 782        for (i = 0; i < kctl->count; i++)
 783                kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
 784        kctl->info = hdmi_chmap_ctl_info;
 785        kctl->get = hdmi_chmap_ctl_get;
 786        kctl->put = hdmi_chmap_ctl_put;
 787        kctl->tlv.c = hdmi_chmap_ctl_tlv;
 788
 789        return 0;
 790}
 791EXPORT_SYMBOL_GPL(snd_hdac_add_chmap_ctls);
 792