aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-07-31 05:36:00 -0400
committerTakashi Iwai <tiwai@suse.de>2012-09-06 12:08:26 -0400
commitd45e6889ee69456a4d5b1bbb32252f460cd48fa9 (patch)
treef7a55c4c45925738d9bddfa655933fbb00d73de6 /sound/pci/hda
parent9c9a5175e65b2667001e6a3b6dedddebeee82aa2 (diff)
ALSA: hda - Provide the proper channel mapping for generic HDMI driver
... instead of the standard fixed channel maps. The generic HDMI is based on the audio infoframe, and its configuration can be selected via CA bits. Thus we need a translation between the CA index and the verbose channel map list. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/patch_hdmi.c308
1 files changed, 303 insertions, 5 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 333d5338c15c..4a5d24fe8adf 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -35,6 +35,7 @@
35#include <sound/core.h> 35#include <sound/core.h>
36#include <sound/jack.h> 36#include <sound/jack.h>
37#include <sound/asoundef.h> 37#include <sound/asoundef.h>
38#include <sound/tlv.h>
38#include "hda_codec.h" 39#include "hda_codec.h"
39#include "hda_local.h" 40#include "hda_local.h"
40#include "hda_jack.h" 41#include "hda_jack.h"
@@ -73,6 +74,8 @@ struct hdmi_spec_per_pin {
73 struct delayed_work work; 74 struct delayed_work work;
74 int repoll_count; 75 int repoll_count;
75 bool non_pcm; 76 bool non_pcm;
77 bool chmap_set; /* channel-map override by ALSA API? */
78 unsigned char chmap[8]; /* ALSA API channel-map */
76}; 79};
77 80
78struct hdmi_spec { 81struct hdmi_spec {
@@ -82,6 +85,7 @@ struct hdmi_spec {
82 int num_pins; 85 int num_pins;
83 struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; 86 struct hdmi_spec_per_pin pins[MAX_HDMI_PINS];
84 struct hda_pcm pcm_rec[MAX_HDMI_PINS]; 87 struct hda_pcm pcm_rec[MAX_HDMI_PINS];
88 unsigned int channels_max; /* max over all cvts */
85 89
86 /* 90 /*
87 * Non-generic ATI/NVIDIA specific 91 * Non-generic ATI/NVIDIA specific
@@ -548,7 +552,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
548} 552}
549 553
550 554
551static void hdmi_setup_channel_mapping(struct hda_codec *codec, 555static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
552 hda_nid_t pin_nid, 556 hda_nid_t pin_nid,
553 bool non_pcm, 557 bool non_pcm,
554 int ca) 558 int ca)
@@ -588,6 +592,136 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
588 hdmi_debug_channel_mapping(codec, pin_nid); 592 hdmi_debug_channel_mapping(codec, pin_nid);
589} 593}
590 594
595struct channel_map_table {
596 unsigned char map; /* ALSA API channel map position */
597 unsigned char cea_slot; /* CEA slot value */
598 int spk_mask; /* speaker position bit mask */
599};
600
601static struct channel_map_table map_tables[] = {
602 { SNDRV_CHMAP_FL, 0x00, FL },
603 { SNDRV_CHMAP_FR, 0x01, FR },
604 { SNDRV_CHMAP_RL, 0x04, RL },
605 { SNDRV_CHMAP_RR, 0x05, RR },
606 { SNDRV_CHMAP_LFE, 0x02, LFE },
607 { SNDRV_CHMAP_FC, 0x03, FC },
608 { SNDRV_CHMAP_RLC, 0x06, RLC },
609 { SNDRV_CHMAP_RRC, 0x07, RRC },
610 {} /* terminator */
611};
612
613/* from ALSA API channel position to speaker bit mask */
614static int to_spk_mask(unsigned char c)
615{
616 struct channel_map_table *t = map_tables;
617 for (; t->map; t++) {
618 if (t->map == c)
619 return t->spk_mask;
620 }
621 return 0;
622}
623
624/* from ALSA API channel position to CEA slot */
625static int to_cea_slot(unsigned char c)
626{
627 struct channel_map_table *t = map_tables;
628 for (; t->map; t++) {
629 if (t->map == c)
630 return t->cea_slot;
631 }
632 return 0x0f;
633}
634
635/* from CEA slot to ALSA API channel position */
636static int from_cea_slot(unsigned char c)
637{
638 struct channel_map_table *t = map_tables;
639 for (; t->map; t++) {
640 if (t->cea_slot == c)
641 return t->map;
642 }
643 return 0;
644}
645
646/* from speaker bit mask to ALSA API channel position */
647static int spk_to_chmap(int spk)
648{
649 struct channel_map_table *t = map_tables;
650 for (; t->map; t++) {
651 if (t->spk_mask == spk)
652 return t->map;
653 }
654 return 0;
655}
656
657/* get the CA index corresponding to the given ALSA API channel map */
658static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
659{
660 int i, spks = 0, spk_mask = 0;
661
662 for (i = 0; i < chs; i++) {
663 int mask = to_spk_mask(map[i]);
664 if (mask) {
665 spk_mask |= mask;
666 spks++;
667 }
668 }
669
670 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
671 if ((chs == channel_allocations[i].channels ||
672 spks == channel_allocations[i].channels) &&
673 (spk_mask & channel_allocations[i].spk_mask) ==
674 channel_allocations[i].spk_mask)
675 return channel_allocations[i].ca_index;
676 }
677 return -1;
678}
679
680/* set up the channel slots for the given ALSA API channel map */
681static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
682 hda_nid_t pin_nid,
683 int chs, unsigned char *map)
684{
685 int i;
686 for (i = 0; i < 8; i++) {
687 int val, err;
688 if (i < chs)
689 val = to_cea_slot(map[i]);
690 else
691 val = 0xf;
692 val |= (i << 4);
693 err = snd_hda_codec_write(codec, pin_nid, 0,
694 AC_VERB_SET_HDMI_CHAN_SLOT, val);
695 if (err)
696 return -EINVAL;
697 }
698 return 0;
699}
700
701/* store ALSA API channel map from the current default map */
702static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
703{
704 int i;
705 for (i = 0; i < 8; i++) {
706 if (i < channel_allocations[ca].channels)
707 map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f);
708 else
709 map[i] = 0;
710 }
711}
712
713static void hdmi_setup_channel_mapping(struct hda_codec *codec,
714 hda_nid_t pin_nid, bool non_pcm, int ca,
715 int channels, unsigned char *map)
716{
717 if (!non_pcm && map) {
718 hdmi_manual_setup_channel_mapping(codec, pin_nid,
719 channels, map);
720 } else {
721 hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
722 hdmi_setup_fake_chmap(map, ca);
723 }
724}
591 725
592/* 726/*
593 * Audio InfoFrame routines 727 * Audio InfoFrame routines
@@ -726,7 +860,12 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
726 if (!eld->monitor_present) 860 if (!eld->monitor_present)
727 return; 861 return;
728 862
729 ca = hdmi_channel_allocation(eld, channels); 863 if (!non_pcm && per_pin->chmap_set)
864 ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
865 else
866 ca = hdmi_channel_allocation(eld, channels);
867 if (ca < 0)
868 ca = 0;
730 869
731 memset(&ai, 0, sizeof(ai)); 870 memset(&ai, 0, sizeof(ai));
732 if (eld->conn_type == 0) { /* HDMI */ 871 if (eld->conn_type == 0) { /* HDMI */
@@ -763,7 +902,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
763 "pin=%d channels=%d\n", 902 "pin=%d channels=%d\n",
764 pin_nid, 903 pin_nid,
765 channels); 904 channels);
766 hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca); 905 hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
906 channels, per_pin->chmap);
767 hdmi_stop_infoframe_trans(codec, pin_nid); 907 hdmi_stop_infoframe_trans(codec, pin_nid);
768 hdmi_fill_audio_infoframe(codec, pin_nid, 908 hdmi_fill_audio_infoframe(codec, pin_nid,
769 ai.bytes, sizeof(ai)); 909 ai.bytes, sizeof(ai));
@@ -772,7 +912,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
772 /* For non-pcm audio switch, setup new channel mapping 912 /* For non-pcm audio switch, setup new channel mapping
773 * accordingly */ 913 * accordingly */
774 if (per_pin->non_pcm != non_pcm) 914 if (per_pin->non_pcm != non_pcm)
775 hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca); 915 hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
916 channels, per_pin->chmap);
776 } 917 }
777 918
778 per_pin->non_pcm = non_pcm; 919 per_pin->non_pcm = non_pcm;
@@ -1098,8 +1239,11 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
1098 1239
1099 per_cvt->cvt_nid = cvt_nid; 1240 per_cvt->cvt_nid = cvt_nid;
1100 per_cvt->channels_min = 2; 1241 per_cvt->channels_min = 2;
1101 if (chans <= 16) 1242 if (chans <= 16) {
1102 per_cvt->channels_max = chans; 1243 per_cvt->channels_max = chans;
1244 if (chans > spec->channels_max)
1245 spec->channels_max = chans;
1246 }
1103 1247
1104 err = snd_hda_query_supported_pcm(codec, cvt_nid, 1248 err = snd_hda_query_supported_pcm(codec, cvt_nid,
1105 &per_cvt->rates, 1249 &per_cvt->rates,
@@ -1250,7 +1394,10 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
1250 AC_VERB_SET_PIN_WIDGET_CONTROL, 1394 AC_VERB_SET_PIN_WIDGET_CONTROL,
1251 pinctl & ~PIN_OUT); 1395 pinctl & ~PIN_OUT);
1252 snd_hda_spdif_ctls_unassign(codec, pin_idx); 1396 snd_hda_spdif_ctls_unassign(codec, pin_idx);
1397 per_pin->chmap_set = false;
1398 memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
1253 } 1399 }
1400
1254 return 0; 1401 return 0;
1255} 1402}
1256 1403
@@ -1261,6 +1408,135 @@ static const struct hda_pcm_ops generic_ops = {
1261 .cleanup = generic_hdmi_playback_pcm_cleanup, 1408 .cleanup = generic_hdmi_playback_pcm_cleanup,
1262}; 1409};
1263 1410
1411/*
1412 * ALSA API channel-map control callbacks
1413 */
1414static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
1415 struct snd_ctl_elem_info *uinfo)
1416{
1417 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1418 struct hda_codec *codec = info->private_data;
1419 struct hdmi_spec *spec = codec->spec;
1420 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1421 uinfo->count = spec->channels_max;
1422 uinfo->value.integer.min = 0;
1423 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
1424 return 0;
1425}
1426
1427static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
1428 unsigned int size, unsigned int __user *tlv)
1429{
1430 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1431 struct hda_codec *codec = info->private_data;
1432 struct hdmi_spec *spec = codec->spec;
1433 const unsigned int valid_mask =
1434 FL | FR | RL | RR | LFE | FC | RLC | RRC;
1435 unsigned int __user *dst;
1436 int chs, count = 0;
1437
1438 if (size < 8)
1439 return -ENOMEM;
1440 if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
1441 return -EFAULT;
1442 size -= 8;
1443 dst = tlv + 2;
1444 for (chs = 2; chs <= spec->channels_max; chs += 2) {
1445 int i, c;
1446 struct cea_channel_speaker_allocation *cap;
1447 cap = channel_allocations;
1448 for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
1449 int chs_bytes = chs * 4;
1450 if (cap->channels != chs)
1451 continue;
1452 if (cap->spk_mask & ~valid_mask)
1453 continue;
1454 if (size < 8)
1455 return -ENOMEM;
1456 if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
1457 put_user(chs_bytes, dst + 1))
1458 return -EFAULT;
1459 dst += 2;
1460 size -= 8;
1461 count += 8;
1462 if (size < chs_bytes)
1463 return -ENOMEM;
1464 size -= chs_bytes;
1465 count += chs_bytes;
1466 for (c = 7; c >= 0; c--) {
1467 int spk = cap->speakers[c];
1468 if (!spk)
1469 continue;
1470 if (put_user(spk_to_chmap(spk), dst))
1471 return -EFAULT;
1472 dst++;
1473 }
1474 }
1475 }
1476 if (put_user(count, tlv + 1))
1477 return -EFAULT;
1478 return 0;
1479}
1480
1481static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
1482 struct snd_ctl_elem_value *ucontrol)
1483{
1484 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1485 struct hda_codec *codec = info->private_data;
1486 struct hdmi_spec *spec = codec->spec;
1487 int pin_idx = kcontrol->private_value;
1488 struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
1489 int i;
1490
1491 for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
1492 ucontrol->value.integer.value[i] = per_pin->chmap[i];
1493 return 0;
1494}
1495
1496static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
1497 struct snd_ctl_elem_value *ucontrol)
1498{
1499 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
1500 struct hda_codec *codec = info->private_data;
1501 struct hdmi_spec *spec = codec->spec;
1502 int pin_idx = kcontrol->private_value;
1503 struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx];
1504 unsigned int ctl_idx;
1505 struct snd_pcm_substream *substream;
1506 unsigned char chmap[8];
1507 int i, ca, prepared = 0;
1508
1509 ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
1510 substream = snd_pcm_chmap_substream(info, ctl_idx);
1511 if (!substream || !substream->runtime)
1512 return -EBADFD;
1513 switch (substream->runtime->status->state) {
1514 case SNDRV_PCM_STATE_OPEN:
1515 case SNDRV_PCM_STATE_SETUP:
1516 break;
1517 case SNDRV_PCM_STATE_PREPARED:
1518 prepared = 1;
1519 break;
1520 default:
1521 return -EBUSY;
1522 }
1523 memset(chmap, 0, sizeof(chmap));
1524 for (i = 0; i < ARRAY_SIZE(chmap); i++)
1525 chmap[i] = ucontrol->value.integer.value[i];
1526 if (!memcmp(chmap, per_pin->chmap, sizeof(chmap)))
1527 return 0;
1528 ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
1529 if (ca < 0)
1530 return -EINVAL;
1531 per_pin->chmap_set = true;
1532 memcpy(per_pin->chmap, chmap, sizeof(chmap));
1533 if (prepared)
1534 hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm,
1535 substream);
1536
1537 return 0;
1538}
1539
1264static int generic_hdmi_build_pcms(struct hda_codec *codec) 1540static int generic_hdmi_build_pcms(struct hda_codec *codec)
1265{ 1541{
1266 struct hdmi_spec *spec = codec->spec; 1542 struct hdmi_spec *spec = codec->spec;
@@ -1273,6 +1549,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
1273 info = &spec->pcm_rec[pin_idx]; 1549 info = &spec->pcm_rec[pin_idx];
1274 info->name = get_hdmi_pcm_name(pin_idx); 1550 info->name = get_hdmi_pcm_name(pin_idx);
1275 info->pcm_type = HDA_PCM_TYPE_HDMI; 1551 info->pcm_type = HDA_PCM_TYPE_HDMI;
1552 info->own_chmap = true;
1276 1553
1277 pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; 1554 pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
1278 pstr->substreams = 1; 1555 pstr->substreams = 1;
@@ -1330,6 +1607,27 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
1330 hdmi_present_sense(per_pin, 0); 1607 hdmi_present_sense(per_pin, 0);
1331 } 1608 }
1332 1609
1610 /* add channel maps */
1611 for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
1612 struct snd_pcm_chmap *chmap;
1613 struct snd_kcontrol *kctl;
1614 int i;
1615 err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm,
1616 SNDRV_PCM_STREAM_PLAYBACK,
1617 NULL, 0, pin_idx, &chmap);
1618 if (err < 0)
1619 return err;
1620 /* override handlers */
1621 chmap->private_data = codec;
1622 kctl = chmap->kctl;
1623 for (i = 0; i < kctl->count; i++)
1624 kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE;
1625 kctl->info = hdmi_chmap_ctl_info;
1626 kctl->get = hdmi_chmap_ctl_get;
1627 kctl->put = hdmi_chmap_ctl_put;
1628 kctl->tlv.c = hdmi_chmap_ctl_tlv;
1629 }
1630
1333 return 0; 1631 return 0;
1334} 1632}
1335 1633