[alsa-devel] [PATCH v3 0/7] ALSA: hda: Move chmap helpers to core
The HDMI channel map helper APIs and control registration can be reused by ASoC skylake HDMI drivers.
A common chmap object is created, channel map control callback handlers, helper APIs and data structures are moved to the core. Driver object store an instance of this chmap object to register chmap controls and program channel allocation for HDMI infoframe. Driver registers ops for specific operations.
changes in v3: - Namespace managed as per hda frmwrk requirement - Address review comments in v2
Subhransu S. Prusty (7): ALSA: hda - Create common chmap object ALSA: hda - Register chmap obj as priv data instead of codec ALSA: hda - Use hdac name space for CEA spk alloc structure ALSA: hda - Add hdmi chmap verb programming ops to chmap object ALSA: hda - chmap helper args modified to use generic hdac objs. ALSA: hda - Move chmap support helpers/ops to core ALSA: hda - Use snd_hdac namespace prefix for chmap exported APIs
include/sound/hda_chmap.h | 76 +++++ sound/hda/Makefile | 2 +- sound/hda/hdmi_chmap.c | 791 +++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_eld.c | 31 +- sound/pci/hda/patch_hdmi.c | 824 +++++---------------------------------------- 5 files changed, 950 insertions(+), 774 deletions(-) create mode 100644 include/sound/hda_chmap.h create mode 100644 sound/hda/hdmi_chmap.c
chmap object represents multichannel capability and contains chmap ops. Legacy driver is updated to use this.
With next set of patches chmap object is moved to common to be reused by other drivers (ex: skylake ASoC hdmi driver).
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 41 +++++++++++++++++++++++ sound/pci/hda/patch_hdmi.c | 81 +++++++++++++++++++++++----------------------- 2 files changed, 81 insertions(+), 41 deletions(-) create mode 100644 include/sound/hda_chmap.h
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h new file mode 100644 index 0000000..9ab20f0 --- /dev/null +++ b/include/sound/hda_chmap.h @@ -0,0 +1,41 @@ +/* + * For multichannel support + */ + +#ifndef __SOUND_HDA_CHMAP_H +#define __SOUND_HDA_CHMAP_H + +#include <sound/hdaudio.h> + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + int spk_mask; +}; +struct hdac_chmap; + +struct hdac_chmap_ops { + /* + * Helpers for producing the channel map TLVs. These can be overridden + * for devices that have non-standard mapping requirements. + */ + int (*chmap_cea_alloc_validate_get_type)(struct hdac_chmap *chmap, + struct cea_channel_speaker_allocation *cap, int channels); + void (*cea_alloc_to_tlv_chmap) + (struct cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels); + + /* check that the user-given chmap is supported */ + int (*chmap_validate)(int ca, int channels, unsigned char *chmap); +}; + +struct hdac_chmap { + unsigned int channels_max; /* max over all cvts */ + struct hdac_chmap_ops ops; + struct hdac_device *hdac; +}; + +#endif /* __SOUND_HDA_CHMAP_H */ diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 490931d..5f9d975 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -39,6 +39,7 @@ #include <sound/tlv.h> #include <sound/hdaudio.h> #include <sound/hda_i915.h> +#include <sound/hda_chmap.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" @@ -121,15 +122,6 @@ struct hdmi_ops { int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid, u32 stream_tag, int format);
- /* Helpers for producing the channel map TLVs. These can be overridden - * for devices that have non-standard mapping requirements. */ - int (*chmap_cea_alloc_validate_get_type)(struct cea_channel_speaker_allocation *cap, - int channels); - void (*cea_alloc_to_tlv_chmap)(struct cea_channel_speaker_allocation *cap, - unsigned int *chmap, int channels); - - /* check that the user-given chmap is supported */ - int (*chmap_validate)(int ca, int channels, unsigned char *chmap); };
struct hdmi_pcm { @@ -155,7 +147,6 @@ struct hdmi_spec { * bit 1 means the second playback PCM, and so on. */ unsigned long pcm_in_use; - unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld; struct hdmi_ops ops; @@ -171,6 +162,8 @@ struct hdmi_spec { /* i915/powerwell (Haswell+/Valleyview+) specific */ struct i915_audio_component_audio_ops i915_audio_ops; bool i915_bound; /* was i915 bound in this driver? */ + + struct hdac_chmap chmap; };
#ifdef CONFIG_SND_HDA_I915 @@ -264,15 +257,6 @@ static int eld_speaker_allocation_bits[] = { [10] = FCH, };
-struct cea_channel_speaker_allocation { - int ca_index; - int speakers[8]; - - /* derived values, just for convenience */ - int channels; - int spk_mask; -}; - /* * ALSA sequence is: * @@ -2141,8 +2125,8 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) per_cvt->channels_min = 2; if (chans <= 16) { per_cvt->channels_max = chans; - if (chans > spec->channels_max) - spec->channels_max = chans; + if (chans > spec->chmap.channels_max) + spec->chmap.channels_max = chans; }
err = snd_hda_query_supported_pcm(codec, cvt_nid, @@ -2368,15 +2352,17 @@ static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; + struct hdac_chmap *chmap = &spec->chmap; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = spec->channels_max; + uinfo->count = chmap->channels_max; uinfo->value.integer.min = 0; uinfo->value.integer.max = SNDRV_CHMAP_LAST; return 0; }
-static int hdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, - int channels) +static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, + struct cea_channel_speaker_allocation *cap, int channels) { /* If the speaker allocation matches the channel count, it is OK.*/ if (cap->channels != channels) @@ -2409,6 +2395,7 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; + struct hdac_chmap *chmap = &spec->chmap; unsigned int __user *dst; int chs, count = 0;
@@ -2418,13 +2405,14 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; size -= 8; dst = tlv + 2; - for (chs = 2; chs <= spec->channels_max; chs++) { + for (chs = 2; chs <= chmap->channels_max; chs++) { int i; struct 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 = spec->ops.chmap_cea_alloc_validate_get_type(cap, chs); + int type = chmap->ops.chmap_cea_alloc_validate_get_type( + chmap, cap, chs); unsigned int tlv_chmap[8];
if (type < 0) @@ -2441,7 +2429,7 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -ENOMEM; size -= chs_bytes; count += chs_bytes; - spec->ops.cea_alloc_to_tlv_chmap(cap, tlv_chmap, chs); + chmap->ops.cea_alloc_to_tlv_chmap(cap, tlv_chmap, chs); if (copy_to_user(dst, tlv_chmap, chs_bytes)) return -EFAULT; dst += chs; @@ -2458,12 +2446,13 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; + struct hdac_chmap *chmap = &spec->chmap; int pcm_idx = kcontrol->private_value; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); int i;
if (!per_pin) { - for (i = 0; i < spec->channels_max; i++) + for (i = 0; i < chmap->channels_max; i++) ucontrol->value.integer.value[i] = 0; return 0; } @@ -2479,6 +2468,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; + struct hdac_chmap *hchmap = &spec->chmap; int pcm_idx = kcontrol->private_value; struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); unsigned int ctl_idx; @@ -2514,8 +2504,8 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); if (ca < 0) return -EINVAL; - if (spec->ops.chmap_validate) { - err = spec->ops.chmap_validate(ca, ARRAY_SIZE(chmap), chmap); + if (hchmap->ops.chmap_validate) { + err = hchmap->ops.chmap_validate(ca, ARRAY_SIZE(chmap), chmap); if (err) return err; } @@ -2806,6 +2796,9 @@ static const struct hdmi_ops generic_standard_hdmi_ops = { .pin_setup_infoframe = hdmi_pin_setup_infoframe, .pin_hbr_setup = hdmi_pin_hbr_setup, .setup_stream = hdmi_setup_stream, +}; + +static const struct hdac_chmap_ops chmap_ops = { .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type, .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap, }; @@ -2912,6 +2905,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
spec->ops = generic_standard_hdmi_ops; mutex_init(&spec->pcm_lock); + spec->chmap.ops = chmap_ops; + spec->chmap.hdac = &codec->core; codec->spec = spec; hdmi_array_init(spec, 4);
@@ -3498,13 +3493,14 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) * - 0x10de0015 * - 0x10de0040 */ -static int nvhdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, - int channels) +static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, + struct cea_channel_speaker_allocation *cap, int channels) { if (cap->ca_index == 0x00 && channels == 2) return SNDRV_CTL_TLVT_CHMAP_FIXED;
- return hdmi_chmap_cea_alloc_validate_get_type(cap, channels); + return chmap->ops.chmap_cea_alloc_validate_get_type( + chmap, cap, channels); }
static int nvhdmi_chmap_validate(int ca, int chs, unsigned char *map) @@ -3527,9 +3523,9 @@ static int patch_nvhdmi(struct hda_codec *codec) spec = codec->spec; spec->dyn_pin_out = true;
- spec->ops.chmap_cea_alloc_validate_get_type = + spec->chmap.ops.chmap_cea_alloc_validate_get_type = nvhdmi_chmap_cea_alloc_validate_get_type; - spec->ops.chmap_validate = nvhdmi_chmap_validate; + spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
return 0; } @@ -3888,8 +3884,10 @@ static int atihdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_n return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd; }
-static int atihdmi_paired_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, - int channels) +static int atihdmi_paired_chmap_cea_alloc_validate_get_type( + struct hdac_chmap *chmap, + struct cea_channel_speaker_allocation *cap, + int channels) { int c;
@@ -4036,10 +4034,11 @@ static int patch_atihdmi(struct hda_codec *codec)
if (!has_amd_full_remap_support(codec)) { /* override to ATI/AMD-specific versions with pairwise mapping */ - spec->ops.chmap_cea_alloc_validate_get_type = + spec->chmap.ops.chmap_cea_alloc_validate_get_type = atihdmi_paired_chmap_cea_alloc_validate_get_type; - spec->ops.cea_alloc_to_tlv_chmap = atihdmi_paired_cea_alloc_to_tlv_chmap; - spec->ops.chmap_validate = atihdmi_paired_chmap_validate; + spec->chmap.ops.cea_alloc_to_tlv_chmap = + atihdmi_paired_cea_alloc_to_tlv_chmap; + spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; }
/* ATI/AMD converters do not advertise all of their capabilities */ @@ -4051,7 +4050,7 @@ static int patch_atihdmi(struct hda_codec *codec) per_cvt->maxbps = max(per_cvt->maxbps, 24u); }
- spec->channels_max = max(spec->channels_max, 8u); + spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
return 0; }
With this chmap object is added as private data and new ops are added to access driver specific chmap.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 6 +++ sound/pci/hda/patch_hdmi.c | 93 +++++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 34 deletions(-)
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index 9ab20f0..713b2452 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -30,6 +30,12 @@ struct hdac_chmap_ops {
/* check that the user-given chmap is supported */ int (*chmap_validate)(int ca, int channels, unsigned char *chmap); + + void (*get_chmap)(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap); + void (*set_chmap)(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap, int prepared); + bool (*is_pcm_attached)(struct hdac_device *hdac, int pcm_idx); };
struct hdac_chmap { diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5f9d975..04333ec 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -100,8 +100,6 @@ struct hdmi_spec_per_pin { #endif };
-struct cea_channel_speaker_allocation; - /* operations used by generic code that can be overridden by patches */ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, @@ -2350,9 +2348,7 @@ static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hda_codec *codec = info->private_data; - struct hdmi_spec *spec = codec->spec; - struct hdac_chmap *chmap = &spec->chmap; + struct hdac_chmap *chmap = info->private_data;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = chmap->channels_max; @@ -2389,13 +2385,49 @@ static void hdmi_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *c WARN_ON(count != channels); }
+static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap) +{ + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); + + /* chmap is already set to 0 in caller */ + if (!per_pin) + return; + + memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap)); +} + +static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, + unsigned char *chmap, int prepared) +{ + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); + + mutex_lock(&per_pin->lock); + per_pin->chmap_set = true; + memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap)); + if (prepared) + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + mutex_unlock(&per_pin->lock); +} + +static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) +{ + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); + + return per_pin ? true:false; +} + 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 hda_codec *codec = info->private_data; - struct hdmi_spec *spec = codec->spec; - struct hdac_chmap *chmap = &spec->chmap; + struct hdac_chmap *chmap = info->private_data; unsigned int __user *dst; int chs, count = 0;
@@ -2444,21 +2476,17 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hda_codec *codec = info->private_data; - struct hdmi_spec *spec = codec->spec; - struct hdac_chmap *chmap = &spec->chmap; + struct hdac_chmap *chmap = info->private_data; int pcm_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); + unsigned char pcm_chmap[8]; int i;
- if (!per_pin) { - for (i = 0; i < chmap->channels_max; i++) - ucontrol->value.integer.value[i] = 0; - return 0; - } + memset(pcm_chmap, 0, sizeof(pcm_chmap)); + chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap); + + for (i = 0; i < sizeof(chmap); i++) + ucontrol->value.integer.value[i] = pcm_chmap[i];
- for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) - ucontrol->value.integer.value[i] = per_pin->chmap[i]; return 0; }
@@ -2466,20 +2494,17 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hda_codec *codec = info->private_data; - struct hdmi_spec *spec = codec->spec; - struct hdac_chmap *hchmap = &spec->chmap; + struct hdac_chmap *hchmap = info->private_data; int pcm_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); unsigned int ctl_idx; struct snd_pcm_substream *substream; - unsigned char chmap[8]; + unsigned char chmap[8], per_pin_chmap[8]; int i, err, ca, prepared = 0;
/* No monitor is connected in dyn_pcm_assign. * It's invalid to setup the chmap */ - if (!per_pin) + if (!hchmap->ops.is_pcm_attached(hchmap->hdac, pcm_idx)) return 0;
ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); @@ -2499,7 +2524,9 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, memset(chmap, 0, sizeof(chmap)); for (i = 0; i < ARRAY_SIZE(chmap); i++) chmap[i] = ucontrol->value.integer.value[i]; - if (!memcmp(chmap, per_pin->chmap, sizeof(chmap))) + + hchmap->ops.get_chmap(hchmap->hdac, pcm_idx, per_pin_chmap); + if (!memcmp(chmap, per_pin_chmap, sizeof(chmap))) return 0; ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); if (ca < 0) @@ -2509,12 +2536,8 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, if (err) return err; } - mutex_lock(&per_pin->lock); - per_pin->chmap_set = true; - memcpy(per_pin->chmap, chmap, sizeof(chmap)); - if (prepared) - hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); - mutex_unlock(&per_pin->lock); + + hchmap->ops.set_chmap(hchmap->hdac, pcm_idx, chmap, prepared);
return 0; } @@ -2672,7 +2695,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) if (err < 0) return err; /* override handlers */ - chmap->private_data = codec; + chmap->private_data = &spec->chmap; kctl = chmap->kctl; for (i = 0; i < kctl->count; i++) kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; @@ -2801,9 +2824,11 @@ static const struct hdmi_ops generic_standard_hdmi_ops = { static const struct hdac_chmap_ops chmap_ops = { .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type, .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap, + .get_chmap = hdmi_get_chmap, + .set_chmap = hdmi_set_chmap, + .is_pcm_attached = is_hdmi_pcm_attached, };
- static void intel_haswell_fixup_connect_list(struct hda_codec *codec, hda_nid_t nid) {
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 6 +++--- sound/pci/hda/patch_hdmi.c | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index 713b2452..d3f80e7 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -7,7 +7,7 @@
#include <sound/hdaudio.h>
-struct cea_channel_speaker_allocation { +struct hdac_cea_channel_speaker_allocation { int ca_index; int speakers[8];
@@ -23,9 +23,9 @@ struct hdac_chmap_ops { * for devices that have non-standard mapping requirements. */ int (*chmap_cea_alloc_validate_get_type)(struct hdac_chmap *chmap, - struct cea_channel_speaker_allocation *cap, int channels); + struct hdac_cea_channel_speaker_allocation *cap, int channels); void (*cea_alloc_to_tlv_chmap) - (struct cea_channel_speaker_allocation *cap, + (struct hdac_cea_channel_speaker_allocation *cap, unsigned int *chmap, int channels);
/* check that the user-given chmap is supported */ diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 04333ec..d73f54e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -297,7 +297,7 @@ static int hdmi_channel_mapping[0x32][8] = { * The preceding ones have better chances to be selected by * hdmi_channel_allocation(). */ -static struct cea_channel_speaker_allocation channel_allocations[] = { +static struct hdac_cea_channel_speaker_allocation channel_allocations[] = { /* channel: 7 6 5 4 3 2 1 0 */ { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, /* 2.1 */ @@ -683,7 +683,7 @@ static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin) static void init_channel_allocations(void) { int i, j; - struct cea_channel_speaker_allocation *p; + struct hdac_cea_channel_speaker_allocation *p;
for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { p = channel_allocations + i; @@ -791,7 +791,7 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, int ca) { struct hdmi_spec *spec = codec->spec; - struct cea_channel_speaker_allocation *ch_alloc; + struct hdac_cea_channel_speaker_allocation *ch_alloc; int i; int err; int order; @@ -2358,7 +2358,7 @@ static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, }
static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, - struct cea_channel_speaker_allocation *cap, int channels) + struct hdac_cea_channel_speaker_allocation *cap, int channels) { /* If the speaker allocation matches the channel count, it is OK.*/ if (cap->channels != channels) @@ -2368,8 +2368,9 @@ static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, return SNDRV_CTL_TLVT_CHMAP_VAR; }
-static void hdmi_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap, - unsigned int *chmap, int channels) +static void hdmi_cea_alloc_to_tlv_chmap( + struct hdac_cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) { int count = 0; int c; @@ -2439,7 +2440,7 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, dst = tlv + 2; for (chs = 2; chs <= chmap->channels_max; chs++) { int i; - struct cea_channel_speaker_allocation *cap; + 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; @@ -3519,7 +3520,7 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) * - 0x10de0040 */ static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, - struct cea_channel_speaker_allocation *cap, int channels) + struct hdac_cea_channel_speaker_allocation *cap, int channels) { if (cap->ca_index == 0x00 && channels == 2) return SNDRV_CTL_TLVT_CHMAP_FIXED; @@ -3800,7 +3801,7 @@ static int atihdmi_paired_swap_fc_lfe(int pos)
static int atihdmi_paired_chmap_validate(int ca, int chs, unsigned char *map) { - struct cea_channel_speaker_allocation *cap; + struct hdac_cea_channel_speaker_allocation *cap; int i, j;
/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */ @@ -3911,7 +3912,7 @@ static int atihdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_n
static int atihdmi_paired_chmap_cea_alloc_validate_get_type( struct hdac_chmap *chmap, - struct cea_channel_speaker_allocation *cap, + struct hdac_cea_channel_speaker_allocation *cap, int channels) { int c; @@ -3939,8 +3940,9 @@ static int atihdmi_paired_chmap_cea_alloc_validate_get_type( return SNDRV_CTL_TLVT_CHMAP_PAIRED; }
-static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap, - unsigned int *chmap, int channels) +static void atihdmi_paired_cea_alloc_to_tlv_chmap( + struct hdac_cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) { /* produce paired maps for pre-rev3 ATI/AMD codecs */ int count = 0;
Add slot and channel count programming to hdmi_chmap object and move the chmap_ops to core. Use register_chmap_ops API to register for default ops. Override specific chmap ops in the driver.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 10 ++++++ sound/hda/Makefile | 2 +- sound/hda/hdmi_chmap.c | 49 ++++++++++++++++++++++++++ sound/pci/hda/patch_hdmi.c | 87 +++++++++++++++------------------------------- 4 files changed, 88 insertions(+), 60 deletions(-) create mode 100644 sound/hda/hdmi_chmap.c
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index d3f80e7..7afffb9 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -36,6 +36,14 @@ struct hdac_chmap_ops { void (*set_chmap)(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap, int prepared); bool (*is_pcm_attached)(struct hdac_device *hdac, int pcm_idx); + + /* get and set channel assigned to each HDMI ASP (audio sample packet) slot */ + int (*pin_get_slot_channel)(struct hdac_device *codec, + hda_nid_t pin_nid, int asp_slot); + int (*pin_set_slot_channel)(struct hdac_device *codec, + hda_nid_t pin_nid, int asp_slot, int channel); + void (*set_channel_count)(struct hdac_device *codec, + hda_nid_t cvt_nid, int chs); };
struct hdac_chmap { @@ -44,4 +52,6 @@ struct hdac_chmap { struct hdac_device *hdac; };
+void snd_hdac_register_chmap_ops(struct hdac_device *hdac, + struct hdac_chmap *chmap); #endif /* __SOUND_HDA_CHMAP_H */ diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 7e999c9..3b9bede 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -1,5 +1,5 @@ snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \ - hdac_regmap.o hdac_controller.o hdac_stream.o array.o + hdac_regmap.o hdac_controller.o hdac_stream.o array.o hdmi_chmap.o
snd-hda-core-objs += trace.o CFLAGS_trace.o := -I$(src) diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c new file mode 100644 index 0000000..6b98790 --- /dev/null +++ b/sound/hda/hdmi_chmap.c @@ -0,0 +1,49 @@ +/* + * HDMI Channel map support helpers + */ + +#include <sound/hda_chmap.h> + +static int hdmi_pin_set_slot_channel(struct hdac_device *codec, + hda_nid_t pin_nid, int asp_slot, int channel) +{ + return snd_hdac_codec_write(codec, pin_nid, 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + (channel << 4) | asp_slot); +} + +static int hdmi_pin_get_slot_channel(struct hdac_device *codec, + hda_nid_t pin_nid, int asp_slot) +{ + return (snd_hdac_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, + asp_slot) & 0xf0) >> 4; +} + +static int hdmi_get_channel_count(struct hdac_device *codec, hda_nid_t cvt_nid) +{ + return 1 + snd_hdac_codec_read(codec, cvt_nid, 0, + AC_VERB_GET_CVT_CHAN_COUNT, 0); +} + +static void hdmi_set_channel_count(struct hdac_device *codec, + hda_nid_t cvt_nid, int chs) +{ + if (chs != hdmi_get_channel_count(codec, cvt_nid)) + snd_hdac_codec_write(codec, cvt_nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); +} + +static const struct hdac_chmap_ops chmap_ops = { + .pin_get_slot_channel = hdmi_pin_get_slot_channel, + .pin_set_slot_channel = hdmi_pin_set_slot_channel, + .set_channel_count = hdmi_set_channel_count, +}; + +void snd_hdac_register_chmap_ops(struct hdac_device *hdac, + struct hdac_chmap *chmap) +{ + chmap->ops = chmap_ops; + chmap->hdac = hdac; +} +EXPORT_SYMBOL_GPL(snd_hdac_register_chmap_ops); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d73f54e..5dfc839 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -105,12 +105,6 @@ struct hdmi_ops { int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, unsigned char *buf, int *eld_size);
- /* get and set channel assigned to each HDMI ASP (audio sample packet) slot */ - int (*pin_get_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid, - int asp_slot); - int (*pin_set_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid, - int asp_slot, int channel); - void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, int ca, int active_channels, int conn_type);
@@ -596,20 +590,6 @@ static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out); }
-static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) -{ - return 1 + snd_hda_codec_read(codec, cvt_nid, 0, - AC_VERB_GET_CVT_CHAN_COUNT, 0); -} - -static void hdmi_set_channel_count(struct hda_codec *codec, - hda_nid_t cvt_nid, int chs) -{ - if (chs != hdmi_get_channel_count(codec, cvt_nid)) - snd_hda_codec_write(codec, cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); -} - /* * ELD proc files */ @@ -778,7 +758,8 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, int channel;
for (i = 0; i < 8; i++) { - channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i); + channel = spec->chmap.ops.pin_get_slot_channel( + &codec->core, pin_nid, i); codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n", channel, i); } @@ -826,7 +807,8 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]; int hdmi_slot = slotsetup & 0x0f; int channel = (slotsetup & 0xf0) >> 4; - err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel); + err = spec->chmap.ops.pin_set_slot_channel( + &codec->core, pin_nid, hdmi_slot, channel); if (err) { codec_dbg(codec, "HDMI: channel mapping failed\n"); break; @@ -953,8 +935,8 @@ static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec, for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) { int err;
- err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, - assignments[hdmi_slot]); + err = spec->chmap.ops.pin_set_slot_channel(&codec->core, + pin_nid, hdmi_slot, assignments[hdmi_slot]); if (err) return -EINVAL; } @@ -990,22 +972,6 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, hdmi_debug_channel_mapping(codec, pin_nid); }
-static int hdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, - int asp_slot, int channel) -{ - return snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - (channel << 4) | asp_slot); -} - -static int hdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, - int asp_slot) -{ - return (snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_CHAN_SLOT, - asp_slot) & 0xf0) >> 4; -} - /* * Audio InfoFrame routines */ @@ -1181,6 +1147,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, bool non_pcm) { struct hdmi_spec *spec = codec->spec; + struct hdac_chmap *chmap = &spec->chmap; hda_nid_t pin_nid = per_pin->pin_nid; int channels = per_pin->channels; int active_channels; @@ -1207,7 +1174,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, ordered_ca = get_channel_allocation_order(ca); active_channels = channel_allocations[ordered_ca].channels;
- hdmi_set_channel_count(codec, per_pin->cvt_nid, active_channels); + chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid, + active_channels);
/* * always configure channel mapping, it may have been changed by the @@ -2815,21 +2783,11 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
static const struct hdmi_ops generic_standard_hdmi_ops = { .pin_get_eld = snd_hdmi_get_eld, - .pin_get_slot_channel = hdmi_pin_get_slot_channel, - .pin_set_slot_channel = hdmi_pin_set_slot_channel, .pin_setup_infoframe = hdmi_pin_setup_infoframe, .pin_hbr_setup = hdmi_pin_hbr_setup, .setup_stream = hdmi_setup_stream, };
-static const struct hdac_chmap_ops chmap_ops = { - .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type, - .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap, - .get_chmap = hdmi_get_chmap, - .set_chmap = hdmi_set_chmap, - .is_pcm_attached = is_hdmi_pcm_attached, -}; - static void intel_haswell_fixup_connect_list(struct hda_codec *codec, hda_nid_t nid) { @@ -2931,8 +2889,15 @@ static int patch_generic_hdmi(struct hda_codec *codec)
spec->ops = generic_standard_hdmi_ops; mutex_init(&spec->pcm_lock); - spec->chmap.ops = chmap_ops; - spec->chmap.hdac = &codec->core; + snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); + + spec->chmap.ops.chmap_cea_alloc_validate_get_type = + hdmi_chmap_cea_alloc_validate_get_type; + spec->chmap.ops.cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap; + spec->chmap.ops.get_chmap = hdmi_get_chmap; + spec->chmap.ops.set_chmap = hdmi_set_chmap; + spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; + codec->spec = spec; hdmi_array_init(spec, 4);
@@ -3846,9 +3811,10 @@ static int atihdmi_paired_chmap_validate(int ca, int chs, unsigned char *map) return 0; }
-static int atihdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, - int hdmi_slot, int stream_channel) +static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac, + hda_nid_t pin_nid, int hdmi_slot, int stream_channel) { + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); int verb; int ati_channel_setup = 0;
@@ -3881,9 +3847,10 @@ static int atihdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_n return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup); }
-static int atihdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, - int asp_slot) +static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac, + hda_nid_t pin_nid, int asp_slot) { + struct hda_codec *codec = container_of(hdac, struct hda_codec, core); bool was_odd = false; int ati_asp_slot = asp_slot; int verb; @@ -4053,8 +4020,6 @@ static int patch_atihdmi(struct hda_codec *codec) spec = codec->spec;
spec->ops.pin_get_eld = atihdmi_pin_get_eld; - spec->ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; - spec->ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe; spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; spec->ops.setup_stream = atihdmi_setup_stream; @@ -4066,6 +4031,10 @@ static int patch_atihdmi(struct hda_codec *codec) spec->chmap.ops.cea_alloc_to_tlv_chmap = atihdmi_paired_cea_alloc_to_tlv_chmap; spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; + spec->chmap.ops.pin_get_slot_channel = + atihdmi_pin_get_slot_channel; + spec->chmap.ops.pin_set_slot_channel = + atihdmi_pin_set_slot_channel; }
/* ATI/AMD converters do not advertise all of their capabilities */
Chmap helper arguments are modified to use either hdac_device object or hdac_chmap object instead of codec specific object. With this moving these APIs to core will be easier.
Helper added to access a specific channel_allocation object instead of directly accessing.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 10 +++-- sound/pci/hda/patch_hdmi.c | 108 ++++++++++++++++++++++++++++----------------- 2 files changed, 74 insertions(+), 44 deletions(-)
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index 7afffb9..f7fd752 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -7,6 +7,9 @@
#include <sound/hdaudio.h>
+ +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 + struct hdac_cea_channel_speaker_allocation { int ca_index; int speakers[8]; @@ -24,12 +27,13 @@ struct hdac_chmap_ops { */ int (*chmap_cea_alloc_validate_get_type)(struct hdac_chmap *chmap, struct hdac_cea_channel_speaker_allocation *cap, int channels); - void (*cea_alloc_to_tlv_chmap) - (struct hdac_cea_channel_speaker_allocation *cap, + void (*cea_alloc_to_tlv_chmap)(struct hdac_chmap *hchmap, + struct hdac_cea_channel_speaker_allocation *cap, unsigned int *chmap, int channels);
/* check that the user-given chmap is supported */ - int (*chmap_validate)(int ca, int channels, unsigned char *chmap); + int (*chmap_validate)(struct hdac_chmap *hchmap, int ca, + int channels, unsigned char *chmap);
void (*get_chmap)(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5dfc839..b1600d1 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -696,8 +696,8 @@ static int get_channel_allocation_order(int ca) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_channel_allocation(struct hda_codec *codec, - struct hdmi_eld *eld, int channels) +static int hdmi_channel_allocation_spk_alloc_blk(struct hdac_device *codec, + int spk_alloc, int channels) { int i; int ca = 0; @@ -717,7 +717,7 @@ static int hdmi_channel_allocation(struct hda_codec *codec, * expand ELD's notions to match the ones used by Audio InfoFrame. */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (eld->info.spk_alloc & (1 << i)) + if (spk_alloc & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; }
@@ -742,36 +742,34 @@ static int hdmi_channel_allocation(struct hda_codec *codec, } }
- snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); - codec_dbg(codec, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", + snd_print_channel_allocation(spk_alloc, buf, sizeof(buf)); + dev_dbg(&codec->dev, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf);
return ca; }
-static void hdmi_debug_channel_mapping(struct hda_codec *codec, +static void hdmi_debug_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid) { #ifdef CONFIG_SND_DEBUG_VERBOSE - struct hdmi_spec *spec = codec->spec; int i; int channel;
for (i = 0; i < 8; i++) { - channel = spec->chmap.ops.pin_get_slot_channel( - &codec->core, pin_nid, i); - codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n", + channel = chmap->ops.pin_get_slot_channel( + chmap->hdac, pin_nid, i); + dev_dbg(&chmap->hdac->dev, "HDMI: ASP channel %d => slot %d\n", channel, i); } #endif }
-static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, +static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid, bool non_pcm, int ca) { - struct hdmi_spec *spec = codec->spec; struct hdac_cea_channel_speaker_allocation *ch_alloc; int i; int err; @@ -807,10 +805,10 @@ static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]; int hdmi_slot = slotsetup & 0x0f; int channel = (slotsetup & 0xf0) >> 4; - err = spec->chmap.ops.pin_set_slot_channel( - &codec->core, pin_nid, hdmi_slot, channel); + err = chmap->ops.pin_set_slot_channel(chmap->hdac, + pin_nid, hdmi_slot, channel); if (err) { - codec_dbg(codec, "HDMI: channel mapping failed\n"); + dev_dbg(&chmap->hdac->dev, "HDMI: channel mapping failed\n"); break; } } @@ -912,12 +910,11 @@ 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, +static int hdmi_manual_setup_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid, int chs, unsigned char *map, int ca) { - struct hdmi_spec *spec = codec->spec; int ordered_ca = get_channel_allocation_order(ca); int alsa_pos, hdmi_slot; int assignments[8] = {[0 ... 7] = 0xf}; @@ -935,7 +932,7 @@ static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec, for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) { int err;
- err = spec->chmap.ops.pin_set_slot_channel(&codec->core, + err = chmap->ops.pin_set_slot_channel(chmap->hdac, pin_nid, hdmi_slot, assignments[hdmi_slot]); if (err) return -EINVAL; @@ -956,20 +953,20 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca) } }
-static void hdmi_setup_channel_mapping(struct hda_codec *codec, +static void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid, bool non_pcm, int ca, int channels, unsigned char *map, bool chmap_set) { if (!non_pcm && chmap_set) { - hdmi_manual_setup_channel_mapping(codec, pin_nid, + hdmi_manual_setup_channel_mapping(chmap, pin_nid, channels, map, ca); } else { - hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca); + hdmi_std_setup_channel_mapping(chmap, pin_nid, non_pcm, ca); hdmi_setup_fake_chmap(map, ca); }
- hdmi_debug_channel_mapping(codec, pin_nid); + hdmi_debug_channel_mapping(chmap, pin_nid); }
/* @@ -1142,6 +1139,35 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, } }
+static int hdmi_get_active_channels(int ca) +{ + int ordered_ca = get_channel_allocation_order(ca); + + return channel_allocations[ordered_ca].channels; +} + +static struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca) +{ + return &channel_allocations[get_channel_allocation_order(ca)]; +} + +static int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, + int channels, bool chmap_set, bool non_pcm, unsigned char *map) +{ + int ca; + + if (!non_pcm && chmap_set) + ca = hdmi_manual_channel_allocation(channels, map); + else + ca = hdmi_channel_allocation_spk_alloc_blk(hdac, + spk_alloc, channels); + + if (ca < 0) + ca = 0; + + return ca; +} + static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, bool non_pcm) @@ -1152,7 +1178,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int channels = per_pin->channels; int active_channels; struct hdmi_eld *eld; - int ca, ordered_ca; + int ca;
if (!channels) return; @@ -1164,15 +1190,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
eld = &per_pin->sink_eld;
- if (!non_pcm && per_pin->chmap_set) - ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); - else - ca = hdmi_channel_allocation(codec, eld, channels); - if (ca < 0) - ca = 0; + ca = hdmi_channel_allocation(&codec->core, + eld->info.spk_alloc, channels, + per_pin->chmap_set, non_pcm, per_pin->chmap);
- ordered_ca = get_channel_allocation_order(ca); - active_channels = channel_allocations[ordered_ca].channels; + active_channels = hdmi_get_active_channels(ca);
chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid, active_channels); @@ -1181,9 +1203,9 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, * always configure channel mapping, it may have been changed by the * user in the meantime */ - hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, - channels, per_pin->chmap, - per_pin->chmap_set); + hdmi_setup_channel_mapping(&spec->chmap, + pin_nid, non_pcm, ca, channels, + per_pin->chmap, per_pin->chmap_set);
spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels, eld->info.conn_type); @@ -2336,7 +2358,7 @@ static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, return SNDRV_CTL_TLVT_CHMAP_VAR; }
-static void hdmi_cea_alloc_to_tlv_chmap( +static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, struct hdac_cea_channel_speaker_allocation *cap, unsigned int *chmap, int channels) { @@ -2430,7 +2452,8 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -ENOMEM; size -= chs_bytes; count += chs_bytes; - chmap->ops.cea_alloc_to_tlv_chmap(cap, tlv_chmap, chs); + 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; @@ -2501,7 +2524,8 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, if (ca < 0) return -EINVAL; if (hchmap->ops.chmap_validate) { - err = hchmap->ops.chmap_validate(ca, ARRAY_SIZE(chmap), chmap); + err = hchmap->ops.chmap_validate(hchmap, ca, + ARRAY_SIZE(chmap), chmap); if (err) return err; } @@ -3494,7 +3518,8 @@ static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, chmap, cap, channels); }
-static int nvhdmi_chmap_validate(int ca, int chs, unsigned char *map) +static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, + int ca, int chs, unsigned char *map) { if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) return -EINVAL; @@ -3764,14 +3789,15 @@ static int atihdmi_paired_swap_fc_lfe(int pos) return pos; }
-static int atihdmi_paired_chmap_validate(int ca, int chs, unsigned char *map) +static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap, + int ca, int chs, unsigned char *map) { struct hdac_cea_channel_speaker_allocation *cap; int i, j;
/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
- cap = &channel_allocations[get_channel_allocation_order(ca)]; + cap = hdmi_get_ch_alloc_from_ca(ca); for (i = 0; i < chs; ++i) { int mask = to_spk_mask(map[i]); bool ok = false; @@ -3907,7 +3933,7 @@ static int atihdmi_paired_chmap_cea_alloc_validate_get_type( return SNDRV_CTL_TLVT_CHMAP_PAIRED; }
-static void atihdmi_paired_cea_alloc_to_tlv_chmap( +static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, struct hdac_cea_channel_speaker_allocation *cap, unsigned int *chmap, int channels) {
Chmap helpers, ops, controls are moved to core.
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 15 + sound/hda/hdmi_chmap.c | 742 +++++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_eld.c | 27 +- sound/pci/hda/patch_hdmi.c | 689 +---------------------------------------- 4 files changed, 759 insertions(+), 714 deletions(-)
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index f7fd752..5a85b31 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -5,6 +5,7 @@ #ifndef __SOUND_HDA_CHMAP_H #define __SOUND_HDA_CHMAP_H
+#include <sound/pcm.h> #include <sound/hdaudio.h>
@@ -58,4 +59,18 @@ struct hdac_chmap {
void snd_hdac_register_chmap_ops(struct hdac_device *hdac, struct hdac_chmap *chmap); +int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, + int channels, bool chmap_set, + bool non_pcm, unsigned char *map); +int hdmi_get_active_channels(int ca); +void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, + hda_nid_t pin_nid, bool non_pcm, int ca, + int channels, unsigned char *map, + bool chmap_set); +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); +struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca); +int to_spk_mask(unsigned char c); +int spk_to_chmap(int spk); +int snd_hdac_add_chmap_ctls(struct snd_pcm *pcm, int pcm_idx, + struct hdac_chmap *chmap); #endif /* __SOUND_HDA_CHMAP_H */ diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 6b98790..880666a 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -2,8 +2,182 @@ * HDMI Channel map support helpers */
+#include <linux/module.h> +#include <sound/control.h> +#include <sound/tlv.h> #include <sound/hda_chmap.h>
+/* + * CEA speaker placement: + * + * FLH FCH FRH + * FLW FL FLC FC FRC FR FRW + * + * LFE + * TC + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ + FLW = (1 << 11), /* Front Left Wide */ + FRW = (1 << 12), /* Front Right Wide */ + FLH = (1 << 13), /* Front Left High */ + FCH = (1 << 14), /* Front Center High */ + FRH = (1 << 15), /* Front Right High */ + TC = (1 << 16), /* Top Center */ +}; + +static const char * const cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = FLW | FRW, + [8] = FLH | FRH, + [9] = TC, + [10] = FCH, +}; + +/* + * ALSA sequence is: + * + * surround40 surround41 surround50 surround51 surround71 + * ch0 front left = = = = + * ch1 front right = = = = + * ch2 rear left = = = = + * ch3 rear right = = = = + * ch4 LFE center center center + * ch5 LFE LFE + * ch6 side left + * ch7 side right + * + * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR} + */ +static int hdmi_channel_mapping[0x32][8] = { + /* stereo */ + [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* 2.1 */ + [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* Dolby Surround */ + [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* surround40 */ + [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 }, + /* 4ch */ + [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, + /* surround41 */ + [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 }, + /* surround50 */ + [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, + /* surround51 */ + [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 }, + /* 7.1 */ + [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 }, +}; + +/* + * This is an ordered list! + * + * The preceding ones have better chances to be selected by + * hdmi_channel_allocation(). + */ +static struct hdac_cea_channel_speaker_allocation channel_allocations[] = { +/* channel: 7 6 5 4 3 2 1 0 */ +{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, + /* 2.1 */ +{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, + /* Dolby Surround */ +{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, + /* surround40 */ +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, + /* surround41 */ +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, + /* surround50 */ +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* surround51 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, + /* surround71 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, + +{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, +{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, +{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, +}; + static int hdmi_pin_set_slot_channel(struct hdac_device *codec, hda_nid_t pin_nid, int asp_slot, int channel) { @@ -34,7 +208,548 @@ static void hdmi_set_channel_count(struct hdac_device *codec, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); }
+/* + * Channel mapping routines + */ + +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct hdac_cea_channel_speaker_allocation *p; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +static int get_channel_allocation_order(int ca) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channel_allocations[i].ca_index == ca) + break; + } + return i; +} + +void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (spk_alloc & (1 << i)) + j += snprintf(buf + j, buflen - j, " %s", + cea_speaker_allocation_names[i]); + } + buf[j] = '\0'; /* necessary when j == 0 */ +} +EXPORT_SYMBOL_GPL(snd_print_channel_allocation); + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. +*/ +static int hdmi_channel_allocation_spk_alloc_blk(struct hdac_device *codec, + int spk_alloc, int channels) +{ + int i; + int ca = 0; + int spk_mask = 0; + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + /* + * CA defaults to 0 for basic stereo audio + */ + if (channels <= 2) + return 0; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by Audio InfoFrame. + */ + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ca = channel_allocations[i].ca_index; + break; + } + } + + if (!ca) { + /* + * if there was no match, select the regular ALSA channel + * allocation with the matching number of channels + */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels) { + ca = channel_allocations[i].ca_index; + break; + } + } + } + + snd_print_channel_allocation(spk_alloc, buf, sizeof(buf)); + dev_dbg(&codec->dev, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", + ca, channels, buf); + + return ca; +} + +static void hdmi_debug_channel_mapping(struct hdac_chmap *chmap, + hda_nid_t pin_nid) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int channel; + + for (i = 0; i < 8; i++) { + channel = chmap->ops.pin_get_slot_channel( + chmap->hdac, pin_nid, i); + dev_dbg(&chmap->hdac->dev, "HDMI: ASP channel %d => slot %d\n", + channel, i); + } +#endif +} + +static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, + hda_nid_t pin_nid, + bool non_pcm, + int ca) +{ + struct hdac_cea_channel_speaker_allocation *ch_alloc; + int i; + int err; + int order; + int non_pcm_mapping[8]; + + order = get_channel_allocation_order(ca); + ch_alloc = &channel_allocations[order]; + + if (hdmi_channel_mapping[ca][1] == 0) { + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ + for (i = 0; i < ch_alloc->channels; i++) { + while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8)) + hdmi_slot++; /* skip zero slots */ + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) + hdmi_channel_mapping[ca][i++] = (0xf << 4) | hdmi_slot; + } + + if (non_pcm) { + for (i = 0; i < ch_alloc->channels; i++) + non_pcm_mapping[i] = (i << 4) | i; + for (; i < 8; i++) + non_pcm_mapping[i] = (0xf << 4) | i; + } + + for (i = 0; i < 8; i++) { + int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]; + int hdmi_slot = slotsetup & 0x0f; + int channel = (slotsetup & 0xf0) >> 4; + + err = chmap->ops.pin_set_slot_channel(chmap->hdac, + pin_nid, hdmi_slot, channel); + if (err) { + dev_dbg(&chmap->hdac->dev, "HDMI: channel mapping failed\n"); + break; + } + } +} + +struct channel_map_table { + unsigned char map; /* ALSA API channel map position */ + int spk_mask; /* speaker position bit mask */ +}; + +static struct channel_map_table map_tables[] = { + { 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_TFL, FLH }, + { SNDRV_CHMAP_TFR, FRH }, + { SNDRV_CHMAP_FLW, FLW }, + { SNDRV_CHMAP_FRW, FRW }, + { SNDRV_CHMAP_TC, TC }, + { SNDRV_CHMAP_TFC, FCH }, + {} /* terminator */ +}; + +/* from ALSA API channel position to speaker bit mask */ +int to_spk_mask(unsigned char c) +{ + struct channel_map_table *t = map_tables; + + for (; t->map; t++) { + if (t->map == c) + return t->spk_mask; + } + return 0; +} +EXPORT_SYMBOL_GPL(to_spk_mask); + +/* from ALSA API channel position to CEA slot */ +static int to_cea_slot(int ordered_ca, unsigned char pos) +{ + int mask = to_spk_mask(pos); + int i; + + if (mask) { + for (i = 0; i < 8; i++) { + if (channel_allocations[ordered_ca].speakers[7 - i] == mask) + return i; + } + } + + return -1; +} + +/* from speaker bit mask to ALSA API channel position */ +int spk_to_chmap(int spk) +{ + struct channel_map_table *t = map_tables; + + for (; t->map; t++) { + if (t->spk_mask == spk) + return t->map; + } + return 0; +} +EXPORT_SYMBOL_GPL(spk_to_chmap); + +/* 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) +{ + int i, spks = 0, spk_mask = 0; + + for (i = 0; i < chs; i++) { + int mask = to_spk_mask(map[i]); + + if (mask) { + spk_mask |= mask; + spks++; + } + } + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if ((chs == channel_allocations[i].channels || + spks == channel_allocations[i].channels) && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) + return channel_allocations[i].ca_index; + } + return -1; +} + +/* set up the channel slots for the given ALSA API channel map */ +static int hdmi_manual_setup_channel_mapping(struct hdac_chmap *chmap, + hda_nid_t pin_nid, + 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(ordered_ca, map[alsa_pos]); + + if (hdmi_slot < 0) + continue; /* unassigned channel */ + + assignments[hdmi_slot] = alsa_pos; + } + + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) { + int err; + + err = chmap->ops.pin_set_slot_channel(chmap->hdac, + pin_nid, hdmi_slot, assignments[hdmi_slot]); + if (err) + return -EINVAL; + } + return 0; +} + +/* store ALSA API channel map from the current default map */ +static void hdmi_setup_fake_chmap(unsigned char *map, int ca) +{ + int i; + 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(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f); + else + map[i] = 0; + } +} + +void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, + hda_nid_t pin_nid, bool non_pcm, int ca, + int channels, unsigned char *map, + bool chmap_set) +{ + if (!non_pcm && chmap_set) { + hdmi_manual_setup_channel_mapping(chmap, pin_nid, + channels, map, ca); + } else { + hdmi_std_setup_channel_mapping(chmap, pin_nid, non_pcm, ca); + hdmi_setup_fake_chmap(map, ca); + } + + hdmi_debug_channel_mapping(chmap, pin_nid); +} +EXPORT_SYMBOL_GPL(hdmi_setup_channel_mapping); + +int hdmi_get_active_channels(int ca) +{ + int ordered_ca = get_channel_allocation_order(ca); + + return channel_allocations[ordered_ca].channels; +} +EXPORT_SYMBOL_GPL(hdmi_get_active_channels); + +struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca) +{ + return &channel_allocations[get_channel_allocation_order(ca)]; +} +EXPORT_SYMBOL_GPL(hdmi_get_ch_alloc_from_ca); + +int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, + int channels, bool chmap_set, bool non_pcm, unsigned char *map) +{ + int ca; + + if (!non_pcm && chmap_set) + ca = hdmi_manual_channel_allocation(channels, map); + else + ca = hdmi_channel_allocation_spk_alloc_blk(hdac, + spk_alloc, channels); + + if (ca < 0) + ca = 0; + + return ca; +} +EXPORT_SYMBOL_GPL(hdmi_channel_allocation); + +/* + * ALSA API channel-map control callbacks + */ +static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdac_chmap *chmap = info->private_data; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chmap->channels_max; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = SNDRV_CHMAP_LAST; + return 0; +} + +static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, + struct hdac_cea_channel_speaker_allocation *cap, int channels) +{ + /* If the speaker allocation matches the channel count, it is OK.*/ + if (cap->channels != channels) + return -1; + + /* all channels are remappable freely */ + return SNDRV_CTL_TLVT_CHMAP_VAR; +} + +static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, + struct hdac_cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) +{ + int count = 0; + int c; + + for (c = 7; c >= 0; c--) { + int spk = cap->speakers[c]; + + if (!spk) + continue; + + chmap[count++] = spk_to_chmap(spk); + } + + WARN_ON(count != channels); +} + +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; + unsigned int __user *dst; + int chs, count = 0; + + if (size < 8) + return -ENOMEM; + if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) + return -EFAULT; + size -= 8; + dst = tlv + 2; + for (chs = 2; chs <= chmap->channels_max; 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) + continue; + 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; +} + +static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdac_chmap *chmap = info->private_data; + int pcm_idx = kcontrol->private_value; + unsigned char pcm_chmap[8]; + int i; + + memset(pcm_chmap, 0, sizeof(pcm_chmap)); + chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap); + + for (i = 0; i < sizeof(chmap); i++) + ucontrol->value.integer.value[i] = pcm_chmap[i]; + + return 0; +} + +static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdac_chmap *hchmap = info->private_data; + int pcm_idx = kcontrol->private_value; + unsigned int ctl_idx; + struct snd_pcm_substream *substream; + unsigned char chmap[8], per_pin_chmap[8]; + int i, err, ca, prepared = 0; + + /* No monitor is connected in dyn_pcm_assign. + * It's invalid to setup the chmap + */ + if (!hchmap->ops.is_pcm_attached(hchmap->hdac, pcm_idx)) + return 0; + + ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + substream = snd_pcm_chmap_substream(info, ctl_idx); + if (!substream || !substream->runtime) + return 0; /* just for avoiding error from alsactl restore */ + switch (substream->runtime->status->state) { + case SNDRV_PCM_STATE_OPEN: + case SNDRV_PCM_STATE_SETUP: + break; + case SNDRV_PCM_STATE_PREPARED: + prepared = 1; + break; + default: + return -EBUSY; + } + memset(chmap, 0, sizeof(chmap)); + for (i = 0; i < ARRAY_SIZE(chmap); i++) + chmap[i] = ucontrol->value.integer.value[i]; + + hchmap->ops.get_chmap(hchmap->hdac, pcm_idx, per_pin_chmap); + if (!memcmp(chmap, per_pin_chmap, sizeof(chmap))) + return 0; + ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); + if (ca < 0) + return -EINVAL; + if (hchmap->ops.chmap_validate) { + err = hchmap->ops.chmap_validate(hchmap, ca, + ARRAY_SIZE(chmap), chmap); + if (err) + return err; + } + + hchmap->ops.set_chmap(hchmap->hdac, pcm_idx, chmap, prepared); + + return 0; +} + static const struct hdac_chmap_ops chmap_ops = { + .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type, + .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap, .pin_get_slot_channel = hdmi_pin_get_slot_channel, .pin_set_slot_channel = hdmi_pin_set_slot_channel, .set_channel_count = hdmi_set_channel_count, @@ -45,5 +760,32 @@ void snd_hdac_register_chmap_ops(struct hdac_device *hdac, { chmap->ops = chmap_ops; chmap->hdac = hdac; + init_channel_allocations(); } EXPORT_SYMBOL_GPL(snd_hdac_register_chmap_ops); + +int snd_hdac_add_chmap_ctls(struct snd_pcm *pcm, int pcm_idx, + struct hdac_chmap *hchmap) +{ + struct snd_pcm_chmap *chmap; + struct snd_kcontrol *kctl; + int err, i; + + err = snd_pcm_add_chmap_ctls(pcm, + SNDRV_PCM_STREAM_PLAYBACK, + NULL, 0, pcm_idx, &chmap); + if (err < 0) + return err; + /* override handlers */ + chmap->private_data = hchmap; + kctl = chmap->kctl; + for (i = 0; i < kctl->count; i++) + kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; + kctl->info = hdmi_chmap_ctl_info; + kctl->get = hdmi_chmap_ctl_get; + kctl->put = hdmi_chmap_ctl_put; + kctl->tlv.c = hdmi_chmap_ctl_tlv; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_add_chmap_ctls); diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index bc2e082..7c6a973 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <sound/core.h> #include <asm/unaligned.h> +#include <sound/hda_chmap.h> #include "hda_codec.h" #include "hda_local.h"
@@ -42,20 +43,6 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, };
-static const char * const cea_speaker_allocation_names[] = { - /* 0 */ "FL/FR", - /* 1 */ "LFE", - /* 2 */ "FC", - /* 3 */ "RL/RR", - /* 4 */ "RC", - /* 5 */ "FLC/FRC", - /* 6 */ "RLC/RRC", - /* 7 */ "FLW/FRW", - /* 8 */ "FLH/FRH", - /* 9 */ "TC", - /* 10 */ "FCH", -}; - static const char * const eld_connection_type_names[4] = { "HDMI", "DisplayPort", @@ -419,18 +406,6 @@ static void hdmi_show_short_audio_desc(struct hda_codec *codec, a->channels, buf, buf2); }
-void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) -{ - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { - if (spk_alloc & (1 << i)) - j += snprintf(buf + j, buflen - j, " %s", - cea_speaker_allocation_names[i]); - } - buf[j] = '\0'; /* necessary when j == 0 */ -} - void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) { int i; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index b1600d1..ecc5abb 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -198,164 +198,6 @@ union audio_infoframe { };
/* - * CEA speaker placement: - * - * FLH FCH FRH - * FLW FL FLC FC FRC FR FRW - * - * LFE - * TC - * - * RL RLC RC RRC RR - * - * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to - * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. - */ -enum cea_speaker_placement { - FL = (1 << 0), /* Front Left */ - FC = (1 << 1), /* Front Center */ - FR = (1 << 2), /* Front Right */ - FLC = (1 << 3), /* Front Left Center */ - FRC = (1 << 4), /* Front Right Center */ - RL = (1 << 5), /* Rear Left */ - RC = (1 << 6), /* Rear Center */ - RR = (1 << 7), /* Rear Right */ - RLC = (1 << 8), /* Rear Left Center */ - RRC = (1 << 9), /* Rear Right Center */ - LFE = (1 << 10), /* Low Frequency Effect */ - FLW = (1 << 11), /* Front Left Wide */ - FRW = (1 << 12), /* Front Right Wide */ - FLH = (1 << 13), /* Front Left High */ - FCH = (1 << 14), /* Front Center High */ - FRH = (1 << 15), /* Front Right High */ - TC = (1 << 16), /* Top Center */ -}; - -/* - * ELD SA bits in the CEA Speaker Allocation data block - */ -static int eld_speaker_allocation_bits[] = { - [0] = FL | FR, - [1] = LFE, - [2] = FC, - [3] = RL | RR, - [4] = RC, - [5] = FLC | FRC, - [6] = RLC | RRC, - /* the following are not defined in ELD yet */ - [7] = FLW | FRW, - [8] = FLH | FRH, - [9] = TC, - [10] = FCH, -}; - -/* - * ALSA sequence is: - * - * surround40 surround41 surround50 surround51 surround71 - * ch0 front left = = = = - * ch1 front right = = = = - * ch2 rear left = = = = - * ch3 rear right = = = = - * ch4 LFE center center center - * ch5 LFE LFE - * ch6 side left - * ch7 side right - * - * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR} - */ -static int hdmi_channel_mapping[0x32][8] = { - /* stereo */ - [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* 2.1 */ - [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* Dolby Surround */ - [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 }, - /* surround40 */ - [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 }, - /* 4ch */ - [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, - /* surround41 */ - [0x09] = { 0x00, 0x11, 0x24, 0x35, 0x42, 0xf3, 0xf6, 0xf7 }, - /* surround50 */ - [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, - /* surround51 */ - [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 }, - /* 7.1 */ - [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 }, -}; - -/* - * This is an ordered list! - * - * The preceding ones have better chances to be selected by - * hdmi_channel_allocation(). - */ -static struct hdac_cea_channel_speaker_allocation channel_allocations[] = { -/* channel: 7 6 5 4 3 2 1 0 */ -{ .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, - /* 2.1 */ -{ .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, - /* Dolby Surround */ -{ .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, - /* surround40 */ -{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, - /* surround41 */ -{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, - /* surround50 */ -{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, - /* surround51 */ -{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, - /* 6.1 */ -{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, - /* surround71 */ -{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, - -{ .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, -{ .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, -{ .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, -{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, -}; - - -/* * HDMI routines */
@@ -654,322 +496,6 @@ static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin) #endif
/* - * Channel mapping routines - */ - -/* - * Compute derived values in channel_allocations[]. - */ -static void init_channel_allocations(void) -{ - int i, j; - struct hdac_cea_channel_speaker_allocation *p; - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - p = channel_allocations + i; - p->channels = 0; - p->spk_mask = 0; - for (j = 0; j < ARRAY_SIZE(p->speakers); j++) - if (p->speakers[j]) { - p->channels++; - p->spk_mask |= p->speakers[j]; - } - } -} - -static int get_channel_allocation_order(int ca) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channel_allocations[i].ca_index == ca) - break; - } - return i; -} - -/* - * The transformation takes two steps: - * - * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask - * spk_mask => (channel_allocations[]) => ai->CA - * - * TODO: it could select the wrong CA from multiple candidates. -*/ -static int hdmi_channel_allocation_spk_alloc_blk(struct hdac_device *codec, - int spk_alloc, int channels) -{ - int i; - int ca = 0; - int spk_mask = 0; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - - /* - * CA defaults to 0 for basic stereo audio - */ - if (channels <= 2) - return 0; - - /* - * expand ELD's speaker allocation mask - * - * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by Audio InfoFrame. - */ - for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (spk_alloc & (1 << i)) - spk_mask |= eld_speaker_allocation_bits[i]; - } - - /* search for the first working match in the CA table */ - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channels == channel_allocations[i].channels && - (spk_mask & channel_allocations[i].spk_mask) == - channel_allocations[i].spk_mask) { - ca = channel_allocations[i].ca_index; - break; - } - } - - if (!ca) { - /* if there was no match, select the regular ALSA channel - * allocation with the matching number of channels */ - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channels == channel_allocations[i].channels) { - ca = channel_allocations[i].ca_index; - break; - } - } - } - - snd_print_channel_allocation(spk_alloc, buf, sizeof(buf)); - dev_dbg(&codec->dev, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", - ca, channels, buf); - - return ca; -} - -static void hdmi_debug_channel_mapping(struct hdac_chmap *chmap, - hda_nid_t pin_nid) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int channel; - - for (i = 0; i < 8; i++) { - channel = chmap->ops.pin_get_slot_channel( - chmap->hdac, pin_nid, i); - dev_dbg(&chmap->hdac->dev, "HDMI: ASP channel %d => slot %d\n", - channel, i); - } -#endif -} - -static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, - hda_nid_t pin_nid, - bool non_pcm, - int ca) -{ - struct hdac_cea_channel_speaker_allocation *ch_alloc; - int i; - int err; - int order; - int non_pcm_mapping[8]; - - order = get_channel_allocation_order(ca); - ch_alloc = &channel_allocations[order]; - - if (hdmi_channel_mapping[ca][1] == 0) { - int hdmi_slot = 0; - /* fill actual channel mappings in ALSA channel (i) order */ - for (i = 0; i < ch_alloc->channels; i++) { - while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8)) - hdmi_slot++; /* skip zero slots */ - - hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; - } - /* fill the rest of the slots with ALSA channel 0xf */ - for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) - if (!ch_alloc->speakers[7 - hdmi_slot]) - hdmi_channel_mapping[ca][i++] = (0xf << 4) | hdmi_slot; - } - - if (non_pcm) { - for (i = 0; i < ch_alloc->channels; i++) - non_pcm_mapping[i] = (i << 4) | i; - for (; i < 8; i++) - non_pcm_mapping[i] = (0xf << 4) | i; - } - - for (i = 0; i < 8; i++) { - int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]; - int hdmi_slot = slotsetup & 0x0f; - int channel = (slotsetup & 0xf0) >> 4; - err = chmap->ops.pin_set_slot_channel(chmap->hdac, - pin_nid, hdmi_slot, channel); - if (err) { - dev_dbg(&chmap->hdac->dev, "HDMI: channel mapping failed\n"); - break; - } - } -} - -struct channel_map_table { - unsigned char map; /* ALSA API channel map position */ - int spk_mask; /* speaker position bit mask */ -}; - -static struct channel_map_table map_tables[] = { - { 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_TFL, FLH }, - { SNDRV_CHMAP_TFR, FRH }, - { SNDRV_CHMAP_FLW, FLW }, - { SNDRV_CHMAP_FRW, FRW }, - { SNDRV_CHMAP_TC, TC }, - { SNDRV_CHMAP_TFC, FCH }, - {} /* terminator */ -}; - -/* from ALSA API channel position to speaker bit mask */ -static int to_spk_mask(unsigned char c) -{ - struct channel_map_table *t = map_tables; - for (; t->map; t++) { - if (t->map == c) - return t->spk_mask; - } - return 0; -} - -/* from ALSA API channel position to CEA slot */ -static int to_cea_slot(int ordered_ca, unsigned char pos) -{ - int mask = to_spk_mask(pos); - int i; - - if (mask) { - for (i = 0; i < 8; i++) { - if (channel_allocations[ordered_ca].speakers[7 - i] == mask) - return i; - } - } - - return -1; -} - -/* from speaker bit mask to ALSA API channel position */ -static int spk_to_chmap(int spk) -{ - struct channel_map_table *t = map_tables; - for (; t->map; t++) { - if (t->spk_mask == spk) - return t->map; - } - 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) -{ - int i, spks = 0, spk_mask = 0; - - for (i = 0; i < chs; i++) { - int mask = to_spk_mask(map[i]); - if (mask) { - spk_mask |= mask; - spks++; - } - } - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if ((chs == channel_allocations[i].channels || - spks == channel_allocations[i].channels) && - (spk_mask & channel_allocations[i].spk_mask) == - channel_allocations[i].spk_mask) - return channel_allocations[i].ca_index; - } - return -1; -} - -/* set up the channel slots for the given ALSA API channel map */ -static int hdmi_manual_setup_channel_mapping(struct hdac_chmap *chmap, - hda_nid_t pin_nid, - 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(ordered_ca, map[alsa_pos]); - - if (hdmi_slot < 0) - continue; /* unassigned channel */ - - assignments[hdmi_slot] = alsa_pos; - } - - for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) { - int err; - - err = chmap->ops.pin_set_slot_channel(chmap->hdac, - pin_nid, hdmi_slot, assignments[hdmi_slot]); - if (err) - return -EINVAL; - } - return 0; -} - -/* store ALSA API channel map from the current default map */ -static void hdmi_setup_fake_chmap(unsigned char *map, int ca) -{ - int i; - 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(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f); - else - map[i] = 0; - } -} - -static void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, - hda_nid_t pin_nid, bool non_pcm, int ca, - int channels, unsigned char *map, - bool chmap_set) -{ - if (!non_pcm && chmap_set) { - hdmi_manual_setup_channel_mapping(chmap, pin_nid, - channels, map, ca); - } else { - hdmi_std_setup_channel_mapping(chmap, pin_nid, non_pcm, ca); - hdmi_setup_fake_chmap(map, ca); - } - - hdmi_debug_channel_mapping(chmap, pin_nid); -} - -/* * Audio InfoFrame routines */
@@ -1139,35 +665,6 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec, } }
-static int hdmi_get_active_channels(int ca) -{ - int ordered_ca = get_channel_allocation_order(ca); - - return channel_allocations[ordered_ca].channels; -} - -static struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca) -{ - return &channel_allocations[get_channel_allocation_order(ca)]; -} - -static int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, - int channels, bool chmap_set, bool non_pcm, unsigned char *map) -{ - int ca; - - if (!non_pcm && chmap_set) - ca = hdmi_manual_channel_allocation(channels, map); - else - ca = hdmi_channel_allocation_spk_alloc_blk(hdac, - spk_alloc, channels); - - if (ca < 0) - ca = 0; - - return ca; -} - static void hdmi_setup_audio_infoframe(struct hda_codec *codec, struct hdmi_spec_per_pin *per_pin, bool non_pcm) @@ -2331,51 +1828,6 @@ static const struct hda_pcm_ops generic_ops = { .cleanup = generic_hdmi_playback_pcm_cleanup, };
-/* - * ALSA API channel-map control callbacks - */ -static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hdac_chmap *chmap = info->private_data; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = chmap->channels_max; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = SNDRV_CHMAP_LAST; - return 0; -} - -static int hdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, - struct hdac_cea_channel_speaker_allocation *cap, int channels) -{ - /* If the speaker allocation matches the channel count, it is OK.*/ - if (cap->channels != channels) - return -1; - - /* all channels are remappable freely */ - return SNDRV_CTL_TLVT_CHMAP_VAR; -} - -static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, - struct hdac_cea_channel_speaker_allocation *cap, - unsigned int *chmap, int channels) -{ - int count = 0; - int c; - - for (c = 7; c >= 0; c--) { - int spk = cap->speakers[c]; - if (!spk) - continue; - - chmap[count++] = spk_to_chmap(spk); - } - - WARN_ON(count != channels); -} - static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, unsigned char *chmap) { @@ -2414,127 +1866,6 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) return per_pin ? true:false; }
-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; - unsigned int __user *dst; - int chs, count = 0; - - if (size < 8) - return -ENOMEM; - if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv)) - return -EFAULT; - size -= 8; - dst = tlv + 2; - for (chs = 2; chs <= chmap->channels_max; 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) - continue; - 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; -} - -static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hdac_chmap *chmap = info->private_data; - int pcm_idx = kcontrol->private_value; - unsigned char pcm_chmap[8]; - int i; - - memset(pcm_chmap, 0, sizeof(pcm_chmap)); - chmap->ops.get_chmap(chmap->hdac, pcm_idx, pcm_chmap); - - for (i = 0; i < sizeof(chmap); i++) - ucontrol->value.integer.value[i] = pcm_chmap[i]; - - return 0; -} - -static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); - struct hdac_chmap *hchmap = info->private_data; - int pcm_idx = kcontrol->private_value; - unsigned int ctl_idx; - struct snd_pcm_substream *substream; - unsigned char chmap[8], per_pin_chmap[8]; - int i, err, ca, prepared = 0; - - /* No monitor is connected in dyn_pcm_assign. - * It's invalid to setup the chmap - */ - if (!hchmap->ops.is_pcm_attached(hchmap->hdac, pcm_idx)) - return 0; - - ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - substream = snd_pcm_chmap_substream(info, ctl_idx); - if (!substream || !substream->runtime) - return 0; /* just for avoiding error from alsactl restore */ - switch (substream->runtime->status->state) { - case SNDRV_PCM_STATE_OPEN: - case SNDRV_PCM_STATE_SETUP: - break; - case SNDRV_PCM_STATE_PREPARED: - prepared = 1; - break; - default: - return -EBUSY; - } - memset(chmap, 0, sizeof(chmap)); - for (i = 0; i < ARRAY_SIZE(chmap); i++) - chmap[i] = ucontrol->value.integer.value[i]; - - hchmap->ops.get_chmap(hchmap->hdac, pcm_idx, per_pin_chmap); - if (!memcmp(chmap, per_pin_chmap, sizeof(chmap))) - return 0; - ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); - if (ca < 0) - return -EINVAL; - if (hchmap->ops.chmap_validate) { - err = hchmap->ops.chmap_validate(hchmap, ca, - ARRAY_SIZE(chmap), chmap); - if (err) - return err; - } - - hchmap->ops.set_chmap(hchmap->hdac, pcm_idx, chmap, prepared); - - return 0; -} - static int generic_hdmi_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; @@ -2675,27 +2006,13 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) /* add channel maps */ for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) { struct hda_pcm *pcm; - struct snd_pcm_chmap *chmap; - struct snd_kcontrol *kctl; - int i;
pcm = get_pcm_rec(spec, pcm_idx); if (!pcm || !pcm->pcm) break; - err = snd_pcm_add_chmap_ctls(pcm->pcm, - SNDRV_PCM_STREAM_PLAYBACK, - NULL, 0, pcm_idx, &chmap); + err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap); if (err < 0) return err; - /* override handlers */ - chmap->private_data = &spec->chmap; - kctl = chmap->kctl; - for (i = 0; i < kctl->count; i++) - kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_WRITE; - kctl->info = hdmi_chmap_ctl_info; - kctl->get = hdmi_chmap_ctl_get; - kctl->put = hdmi_chmap_ctl_put; - kctl->tlv.c = hdmi_chmap_ctl_tlv; }
return 0; @@ -2915,9 +2232,6 @@ static int patch_generic_hdmi(struct hda_codec *codec) mutex_init(&spec->pcm_lock); snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
- spec->chmap.ops.chmap_cea_alloc_validate_get_type = - hdmi_chmap_cea_alloc_validate_get_type; - spec->chmap.ops.cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap; spec->chmap.ops.get_chmap = hdmi_get_chmap; spec->chmap.ops.set_chmap = hdmi_set_chmap; spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached; @@ -2972,7 +2286,6 @@ static int patch_generic_hdmi(struct hda_codec *codec)
generic_hdmi_init_per_pins(codec);
- init_channel_allocations();
WARN_ON(spec->dyn_pcm_assign && !codec_has_acomp(codec)); return 0;
Signed-off-by: Subhransu S. Prusty subhransu.s.prusty@intel.com Signed-off-by: Vinod Koul vinod.koul@intel.com --- include/sound/hda_chmap.h | 14 +++++++------- sound/hda/hdmi_chmap.c | 38 +++++++++++++++++++------------------- sound/pci/hda/hda_eld.c | 4 ++-- sound/pci/hda/patch_hdmi.c | 14 +++++++------- 4 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/include/sound/hda_chmap.h b/include/sound/hda_chmap.h index 5a85b31..e20d219 100644 --- a/include/sound/hda_chmap.h +++ b/include/sound/hda_chmap.h @@ -59,18 +59,18 @@ struct hdac_chmap {
void snd_hdac_register_chmap_ops(struct hdac_device *hdac, struct hdac_chmap *chmap); -int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, +int snd_hdac_channel_allocation(struct hdac_device *hdac, int spk_alloc, int channels, bool chmap_set, bool non_pcm, unsigned char *map); -int hdmi_get_active_channels(int ca); -void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, +int snd_hdac_get_active_channels(int ca); +void snd_hdac_setup_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid, bool non_pcm, int ca, int channels, unsigned char *map, bool chmap_set); -void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); -struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca); -int to_spk_mask(unsigned char c); -int spk_to_chmap(int spk); +void snd_hdac_print_channel_allocation(int spk_alloc, char *buf, int buflen); +struct hdac_cea_channel_speaker_allocation *snd_hdac_get_ch_alloc_from_ca(int ca); +int snd_hdac_chmap_to_spk_mask(unsigned char c); +int snd_hdac_spk_to_chmap(int spk); int snd_hdac_add_chmap_ctls(struct snd_pcm *pcm, int pcm_idx, struct hdac_chmap *chmap); #endif /* __SOUND_HDA_CHMAP_H */ diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index 880666a..d7ec862 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c @@ -243,7 +243,7 @@ static int get_channel_allocation_order(int ca) return i; }
-void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) +void snd_hdac_print_channel_allocation(int spk_alloc, char *buf, int buflen) { int i, j;
@@ -254,7 +254,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) } buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_GPL(snd_print_channel_allocation); +EXPORT_SYMBOL_GPL(snd_hdac_print_channel_allocation);
/* * The transformation takes two steps: @@ -312,7 +312,7 @@ static int hdmi_channel_allocation_spk_alloc_blk(struct hdac_device *codec, } }
- snd_print_channel_allocation(spk_alloc, buf, sizeof(buf)); + snd_hdac_print_channel_allocation(spk_alloc, buf, sizeof(buf)); dev_dbg(&codec->dev, "HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf);
@@ -412,7 +412,7 @@ static struct channel_map_table map_tables[] = { };
/* from ALSA API channel position to speaker bit mask */ -int to_spk_mask(unsigned char c) +int snd_hdac_chmap_to_spk_mask(unsigned char c) { struct channel_map_table *t = map_tables;
@@ -422,12 +422,12 @@ int to_spk_mask(unsigned char c) } return 0; } -EXPORT_SYMBOL_GPL(to_spk_mask); +EXPORT_SYMBOL_GPL(snd_hdac_chmap_to_spk_mask);
/* from ALSA API channel position to CEA slot */ static int to_cea_slot(int ordered_ca, unsigned char pos) { - int mask = to_spk_mask(pos); + int mask = snd_hdac_chmap_to_spk_mask(pos); int i;
if (mask) { @@ -441,7 +441,7 @@ static int to_cea_slot(int ordered_ca, unsigned char pos) }
/* from speaker bit mask to ALSA API channel position */ -int spk_to_chmap(int spk) +int snd_hdac_spk_to_chmap(int spk) { struct channel_map_table *t = map_tables;
@@ -451,14 +451,14 @@ int spk_to_chmap(int spk) } return 0; } -EXPORT_SYMBOL_GPL(spk_to_chmap); +EXPORT_SYMBOL_GPL(snd_hdac_spk_to_chmap);
/* 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); + return snd_hdac_spk_to_chmap(mask); }
/* get the CA index corresponding to the given ALSA API channel map */ @@ -467,7 +467,7 @@ static int hdmi_manual_channel_allocation(int chs, unsigned char *map) int i, spks = 0, spk_mask = 0;
for (i = 0; i < chs; i++) { - int mask = to_spk_mask(map[i]); + int mask = snd_hdac_chmap_to_spk_mask(map[i]);
if (mask) { spk_mask |= mask; @@ -530,7 +530,7 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca) } }
-void hdmi_setup_channel_mapping(struct hdac_chmap *chmap, +void snd_hdac_setup_channel_mapping(struct hdac_chmap *chmap, hda_nid_t pin_nid, bool non_pcm, int ca, int channels, unsigned char *map, bool chmap_set) @@ -545,23 +545,23 @@ void hdmi_setup_channel_mapping(struct hdac_chmap *chmap,
hdmi_debug_channel_mapping(chmap, pin_nid); } -EXPORT_SYMBOL_GPL(hdmi_setup_channel_mapping); +EXPORT_SYMBOL_GPL(snd_hdac_setup_channel_mapping);
-int hdmi_get_active_channels(int ca) +int snd_hdac_get_active_channels(int ca) { int ordered_ca = get_channel_allocation_order(ca);
return channel_allocations[ordered_ca].channels; } -EXPORT_SYMBOL_GPL(hdmi_get_active_channels); +EXPORT_SYMBOL_GPL(snd_hdac_get_active_channels);
-struct hdac_cea_channel_speaker_allocation *hdmi_get_ch_alloc_from_ca(int ca) +struct hdac_cea_channel_speaker_allocation *snd_hdac_get_ch_alloc_from_ca(int ca) { return &channel_allocations[get_channel_allocation_order(ca)]; } -EXPORT_SYMBOL_GPL(hdmi_get_ch_alloc_from_ca); +EXPORT_SYMBOL_GPL(snd_hdac_get_ch_alloc_from_ca);
-int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc, +int snd_hdac_channel_allocation(struct hdac_device *hdac, int spk_alloc, int channels, bool chmap_set, bool non_pcm, unsigned char *map) { int ca; @@ -577,7 +577,7 @@ int hdmi_channel_allocation(struct hdac_device *hdac, int spk_alloc,
return ca; } -EXPORT_SYMBOL_GPL(hdmi_channel_allocation); +EXPORT_SYMBOL_GPL(snd_hdac_channel_allocation);
/* * ALSA API channel-map control callbacks @@ -619,7 +619,7 @@ static void hdmi_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, if (!spk) continue;
- chmap[count++] = spk_to_chmap(spk); + chmap[count++] = snd_hdac_spk_to_chmap(spk); }
WARN_ON(count != channels); diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 7c6a973..ba7fe9b 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -416,7 +416,7 @@ void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e)
if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); codec_dbg(codec, "HDMI: available speakers:%s\n", buf); }
@@ -491,7 +491,7 @@ void snd_hdmi_print_eld_info(struct hdmi_eld *eld, snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
- snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index ecc5abb..f59e87b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -687,11 +687,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
eld = &per_pin->sink_eld;
- ca = hdmi_channel_allocation(&codec->core, + ca = snd_hdac_channel_allocation(&codec->core, eld->info.spk_alloc, channels, per_pin->chmap_set, non_pcm, per_pin->chmap);
- active_channels = hdmi_get_active_channels(ca); + active_channels = snd_hdac_get_active_channels(ca);
chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid, active_channels); @@ -700,7 +700,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, * always configure channel mapping, it may have been changed by the * user in the meantime */ - hdmi_setup_channel_mapping(&spec->chmap, + snd_hdac_setup_channel_mapping(&spec->chmap, pin_nid, non_pcm, ca, channels, per_pin->chmap, per_pin->chmap_set);
@@ -3110,9 +3110,9 @@ static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
/* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
- cap = hdmi_get_ch_alloc_from_ca(ca); + cap = snd_hdac_get_ch_alloc_from_ca(ca); for (i = 0; i < chs; ++i) { - int mask = to_spk_mask(map[i]); + int mask = snd_hdac_chmap_to_spk_mask(map[i]); bool ok = false; bool companion_ok = false;
@@ -3128,7 +3128,7 @@ static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap, if (i % 2 == 0 && i + 1 < chs) { /* even channel, check the odd companion */ int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1); - int comp_mask_req = to_spk_mask(map[i+1]); + int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]); int comp_mask_act = cap->speakers[comp_chan_idx];
if (comp_mask_req == comp_mask_act) @@ -3265,7 +3265,7 @@ static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap, continue; }
- chmap[count++] = spk_to_chmap(spk); + chmap[count++] = snd_hdac_spk_to_chmap(spk); }
WARN_ON(count != channels);
On Fri, 04 Mar 2016 15:29:45 +0100, Subhransu S. Prusty wrote:
The HDMI channel map helper APIs and control registration can be reused by ASoC skylake HDMI drivers.
A common chmap object is created, channel map control callback handlers, helper APIs and data structures are moved to the core. Driver object store an instance of this chmap object to register chmap controls and program channel allocation for HDMI infoframe. Driver registers ops for specific operations.
changes in v3:
- Namespace managed as per hda frmwrk requirement
- Address review comments in v2
Subhransu S. Prusty (7): ALSA: hda - Create common chmap object ALSA: hda - Register chmap obj as priv data instead of codec ALSA: hda - Use hdac name space for CEA spk alloc structure ALSA: hda - Add hdmi chmap verb programming ops to chmap object ALSA: hda - chmap helper args modified to use generic hdac objs. ALSA: hda - Move chmap support helpers/ops to core ALSA: hda - Use snd_hdac namespace prefix for chmap exported APIs
Applied all patches. Thanks.
Takashi
participants (2)
-
Subhransu S. Prusty
-
Takashi Iwai