Skip to content

Commit

Permalink
ALSA: hda - Create common chmap object
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Subhransu S. Prusty authored and Takashi Iwai committed Mar 7, 2016
1 parent cdb1ee3 commit 67b90cb
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 41 deletions.
41 changes: 41 additions & 0 deletions include/sound/hda_chmap.h
Original file line number Diff line number Diff line change
@@ -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 */
81 changes: 40 additions & 41 deletions sound/pci/hda/patch_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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:
*
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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,
};
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -3503,13 +3498,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)
Expand All @@ -3532,9 +3528,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;
}
Expand Down Expand Up @@ -3893,8 +3889,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;

Expand Down Expand Up @@ -4041,10 +4039,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 */
Expand All @@ -4056,7 +4055,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;
}
Expand Down

0 comments on commit 67b90cb

Please sign in to comment.