Commit bce0d2a8 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Allow unlimited pins and converters in patch_hdmi.c

Use the dynamic array allocations for pins, converters and PCM arrays
instead of the fixed size arrays.  The modern HDMI codecs get more and
more pins, and we don't know the sensitive limit.

Most of the patch are spent for the straight conversions from the
fixed array access to snd_array helpers.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 5265fd9a
...@@ -44,16 +44,6 @@ static bool static_hdmi_pcm; ...@@ -44,16 +44,6 @@ static bool static_hdmi_pcm;
module_param(static_hdmi_pcm, bool, 0644); module_param(static_hdmi_pcm, bool, 0644);
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
/*
* The HDMI/DisplayPort configuration can be highly dynamic. A graphics device
* could support N independent pipes, each of them can be connected to one or
* more ports (DVI, HDMI or DisplayPort).
*
* The HDA correspondence of pipes/ports are converter/pin nodes.
*/
#define MAX_HDMI_CVTS 8
#define MAX_HDMI_PINS 8
struct hdmi_spec_per_cvt { struct hdmi_spec_per_cvt {
hda_nid_t cvt_nid; hda_nid_t cvt_nid;
int assigned; int assigned;
...@@ -80,16 +70,17 @@ struct hdmi_spec_per_pin { ...@@ -80,16 +70,17 @@ struct hdmi_spec_per_pin {
bool non_pcm; bool non_pcm;
bool chmap_set; /* channel-map override by ALSA API? */ bool chmap_set; /* channel-map override by ALSA API? */
unsigned char chmap[8]; /* ALSA API channel-map */ unsigned char chmap[8]; /* ALSA API channel-map */
char pcm_name[8]; /* filled in build_pcm callbacks */
}; };
struct hdmi_spec { struct hdmi_spec {
int num_cvts; int num_cvts;
struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; struct snd_array cvts; /* struct hdmi_spec_per_cvt */
hda_nid_t cvt_nids[MAX_HDMI_CVTS]; hda_nid_t cvt_nids[4]; /* only for haswell fix */
int num_pins; int num_pins;
struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; struct snd_array pins; /* struct hdmi_spec_per_pin */
struct hda_pcm pcm_rec[MAX_HDMI_PINS]; struct snd_array pcm_rec; /* struct hda_pcm */
unsigned int channels_max; /* max over all cvts */ unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld; struct hdmi_eld temp_eld;
...@@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { ...@@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = {
* HDMI routines * HDMI routines
*/ */
#define get_pin(spec, idx) \
((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
#define get_cvt(spec, idx) \
((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx))
#define get_pcm_rec(spec, idx) \
((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx))
static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid)
{ {
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
if (spec->pins[pin_idx].pin_nid == pin_nid) if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
return pin_idx; return pin_idx;
snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid);
...@@ -322,7 +320,7 @@ static int hinfo_to_pin_index(struct hdmi_spec *spec, ...@@ -322,7 +320,7 @@ static int hinfo_to_pin_index(struct hdmi_spec *spec,
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
if (&spec->pcm_rec[pin_idx].stream[0] == hinfo) if (get_pcm_rec(spec, pin_idx)->stream == hinfo)
return pin_idx; return pin_idx;
snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo);
...@@ -334,7 +332,7 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) ...@@ -334,7 +332,7 @@ static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid)
int cvt_idx; int cvt_idx;
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
if (spec->cvts[cvt_idx].cvt_nid == cvt_nid) if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
return cvt_idx; return cvt_idx;
snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid);
...@@ -352,7 +350,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, ...@@ -352,7 +350,7 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
pin_idx = kcontrol->private_value; pin_idx = kcontrol->private_value;
eld = &spec->pins[pin_idx].sink_eld; eld = &get_pin(spec, pin_idx)->sink_eld;
mutex_lock(&eld->lock); mutex_lock(&eld->lock);
uinfo->count = eld->eld_valid ? eld->eld_size : 0; uinfo->count = eld->eld_valid ? eld->eld_size : 0;
...@@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, ...@@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
int pin_idx; int pin_idx;
pin_idx = kcontrol->private_value; pin_idx = kcontrol->private_value;
eld = &spec->pins[pin_idx].sink_eld; eld = &get_pin(spec, pin_idx)->sink_eld;
mutex_lock(&eld->lock); mutex_lock(&eld->lock);
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
...@@ -410,11 +408,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx, ...@@ -410,11 +408,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx,
kctl->private_value = pin_idx; kctl->private_value = pin_idx;
kctl->id.device = device; kctl->id.device = device;
err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl); err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl);
if (err < 0) if (err < 0)
return err; return err;
spec->pins[pin_idx].eld_ctl = kctl; get_pin(spec, pin_idx)->eld_ctl = kctl;
return 0; return 0;
} }
...@@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, ...@@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid; hda_nid_t pin_nid = per_pin->pin_nid;
int channels = substream->runtime->channels; int channels = substream->runtime->channels;
struct hdmi_eld *eld; struct hdmi_eld *eld;
int ca; int ca;
union audio_infoframe ai; union audio_infoframe ai;
eld = &spec->pins[pin_idx].sink_eld; eld = &per_pin->sink_eld;
if (!eld->monitor_present) if (!eld->monitor_present)
return; return;
...@@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) ...@@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
if (pin_idx < 0) if (pin_idx < 0)
return; return;
hdmi_present_sense(&spec->pins[pin_idx], 1); hdmi_present_sense(get_pin(spec, pin_idx), 1);
snd_hda_jack_report_sync(codec); snd_hda_jack_report_sync(codec);
} }
...@@ -1083,12 +1081,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -1083,12 +1081,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
pin_idx = hinfo_to_pin_index(spec, hinfo); pin_idx = hinfo_to_pin_index(spec, hinfo);
if (snd_BUG_ON(pin_idx < 0)) if (snd_BUG_ON(pin_idx < 0))
return -EINVAL; return -EINVAL;
per_pin = &spec->pins[pin_idx]; per_pin = get_pin(spec, pin_idx);
eld = &per_pin->sink_eld; eld = &per_pin->sink_eld;
/* Dynamically assign converter to stream */ /* Dynamically assign converter to stream */
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
per_cvt = &spec->cvts[cvt_idx]; per_cvt = get_cvt(spec, cvt_idx);
/* Must not already be assigned */ /* Must not already be assigned */
if (per_cvt->assigned) if (per_cvt->assigned)
...@@ -1151,7 +1149,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, ...@@ -1151,7 +1149,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid; hda_nid_t pin_nid = per_pin->pin_nid;
if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
...@@ -1275,14 +1273,13 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) ...@@ -1275,14 +1273,13 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
return 0; return 0;
if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS))
return -E2BIG;
if (codec->vendor_id == 0x80862807) if (codec->vendor_id == 0x80862807)
intel_haswell_fixup_connect_list(codec, pin_nid); intel_haswell_fixup_connect_list(codec, pin_nid);
pin_idx = spec->num_pins; pin_idx = spec->num_pins;
per_pin = &spec->pins[pin_idx]; per_pin = snd_array_new(&spec->pins);
if (!per_pin)
return -ENOMEM;
per_pin->pin_nid = pin_nid; per_pin->pin_nid = pin_nid;
per_pin->non_pcm = false; per_pin->non_pcm = false;
...@@ -1299,19 +1296,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) ...@@ -1299,19 +1296,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int cvt_idx;
struct hdmi_spec_per_cvt *per_cvt; struct hdmi_spec_per_cvt *per_cvt;
unsigned int chans; unsigned int chans;
int err; int err;
if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS))
return -E2BIG;
chans = get_wcaps(codec, cvt_nid); chans = get_wcaps(codec, cvt_nid);
chans = get_wcaps_channels(chans); chans = get_wcaps_channels(chans);
cvt_idx = spec->num_cvts; per_cvt = snd_array_new(&spec->cvts);
per_cvt = &spec->cvts[cvt_idx]; if (!per_cvt)
return -ENOMEM;
per_cvt->cvt_nid = cvt_nid; per_cvt->cvt_nid = cvt_nid;
per_cvt->channels_min = 2; per_cvt->channels_min = 2;
...@@ -1328,7 +1322,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) ...@@ -1328,7 +1322,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
if (err < 0) if (err < 0)
return err; return err;
spec->cvt_nids[spec->num_cvts++] = cvt_nid; if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
spec->cvt_nids[spec->num_cvts] = cvt_nid;
spec->num_cvts++;
return 0; return 0;
} }
...@@ -1384,13 +1380,6 @@ static int hdmi_parse_codec(struct hda_codec *codec) ...@@ -1384,13 +1380,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
/* /*
*/ */
static char *get_hdmi_pcm_name(int idx)
{
static char names[MAX_HDMI_PINS][8];
sprintf(&names[idx][0], "HDMI %d", idx);
return &names[idx][0];
}
static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
{ {
struct hda_spdif_out *spdif; struct hda_spdif_out *spdif;
...@@ -1417,7 +1406,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -1417,7 +1406,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
hda_nid_t cvt_nid = hinfo->nid; hda_nid_t cvt_nid = hinfo->nid;
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int pin_idx = hinfo_to_pin_index(spec, hinfo); int pin_idx = hinfo_to_pin_index(spec, hinfo);
hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; hda_nid_t pin_nid = get_pin(spec, pin_idx)->pin_nid;
bool non_pcm; bool non_pcm;
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
...@@ -1450,7 +1439,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -1450,7 +1439,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
if (snd_BUG_ON(cvt_idx < 0)) if (snd_BUG_ON(cvt_idx < 0))
return -EINVAL; return -EINVAL;
per_cvt = &spec->cvts[cvt_idx]; per_cvt = get_cvt(spec, cvt_idx);
snd_BUG_ON(!per_cvt->assigned); snd_BUG_ON(!per_cvt->assigned);
per_cvt->assigned = 0; per_cvt->assigned = 0;
...@@ -1459,7 +1448,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, ...@@ -1459,7 +1448,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
pin_idx = hinfo_to_pin_index(spec, hinfo); pin_idx = hinfo_to_pin_index(spec, hinfo);
if (snd_BUG_ON(pin_idx < 0)) if (snd_BUG_ON(pin_idx < 0))
return -EINVAL; return -EINVAL;
per_pin = &spec->pins[pin_idx]; per_pin = get_pin(spec, pin_idx);
snd_hda_spdif_ctls_unassign(codec, pin_idx); snd_hda_spdif_ctls_unassign(codec, pin_idx);
per_pin->chmap_set = false; per_pin->chmap_set = false;
...@@ -1553,7 +1542,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, ...@@ -1553,7 +1542,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol,
struct hda_codec *codec = info->private_data; struct hda_codec *codec = info->private_data;
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int pin_idx = kcontrol->private_value; int pin_idx = kcontrol->private_value;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
int i; int i;
for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++)
...@@ -1568,7 +1557,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, ...@@ -1568,7 +1557,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct hda_codec *codec = info->private_data; struct hda_codec *codec = info->private_data;
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int pin_idx = kcontrol->private_value; int pin_idx = kcontrol->private_value;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
unsigned int ctl_idx; unsigned int ctl_idx;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
unsigned char chmap[8]; unsigned char chmap[8];
...@@ -1613,9 +1602,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -1613,9 +1602,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hda_pcm *info; struct hda_pcm *info;
struct hda_pcm_stream *pstr; struct hda_pcm_stream *pstr;
struct hdmi_spec_per_pin *per_pin;
info = &spec->pcm_rec[pin_idx];
info->name = get_hdmi_pcm_name(pin_idx); per_pin = get_pin(spec, pin_idx);
sprintf(per_pin->pcm_name, "HDMI %d", pin_idx);
info = snd_array_new(&spec->pcm_rec);
if (!info)
return -ENOMEM;
info->name = per_pin->pcm_name;
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
info->own_chmap = true; info->own_chmap = true;
...@@ -1626,7 +1620,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) ...@@ -1626,7 +1620,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
} }
codec->num_pcms = spec->num_pins; codec->num_pcms = spec->num_pins;
codec->pcm_info = spec->pcm_rec; codec->pcm_info = spec->pcm_rec.list;
return 0; return 0;
} }
...@@ -1635,8 +1629,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) ...@@ -1635,8 +1629,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
{ {
char hdmi_str[32] = "HDMI/DP"; char hdmi_str[32] = "HDMI/DP";
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
int pcmdev = spec->pcm_rec[pin_idx].device; int pcmdev = get_pcm_rec(spec, pin_idx)->device;
if (pcmdev > 0) if (pcmdev > 0)
sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
...@@ -1654,7 +1648,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) ...@@ -1654,7 +1648,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
err = generic_hdmi_build_jack(codec, pin_idx); err = generic_hdmi_build_jack(codec, pin_idx);
if (err < 0) if (err < 0)
...@@ -1669,9 +1663,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) ...@@ -1669,9 +1663,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
snd_hda_spdif_ctls_unassign(codec, pin_idx); snd_hda_spdif_ctls_unassign(codec, pin_idx);
/* add control for ELD Bytes */ /* add control for ELD Bytes */
err = hdmi_create_eld_ctl(codec, err = hdmi_create_eld_ctl(codec, pin_idx,
pin_idx, get_pcm_rec(spec, pin_idx)->device);
spec->pcm_rec[pin_idx].device);
if (err < 0) if (err < 0)
return err; return err;
...@@ -1709,7 +1702,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) ...@@ -1709,7 +1702,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
struct hdmi_eld *eld = &per_pin->sink_eld; struct hdmi_eld *eld = &per_pin->sink_eld;
per_pin->codec = codec; per_pin->codec = codec;
...@@ -1726,7 +1719,7 @@ static int generic_hdmi_init(struct hda_codec *codec) ...@@ -1726,7 +1719,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid; hda_nid_t pin_nid = per_pin->pin_nid;
hdmi_init_pin(codec, pin_nid); hdmi_init_pin(codec, pin_nid);
...@@ -1735,13 +1728,27 @@ static int generic_hdmi_init(struct hda_codec *codec) ...@@ -1735,13 +1728,27 @@ static int generic_hdmi_init(struct hda_codec *codec)
return 0; return 0;
} }
static void hdmi_array_init(struct hdmi_spec *spec, int nums)
{
snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums);
}
static void hdmi_array_free(struct hdmi_spec *spec)
{
snd_array_free(&spec->pins);
snd_array_free(&spec->cvts);
snd_array_free(&spec->pcm_rec);
}
static void generic_hdmi_free(struct hda_codec *codec) static void generic_hdmi_free(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int pin_idx; int pin_idx;
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
struct hdmi_eld *eld = &per_pin->sink_eld; struct hdmi_eld *eld = &per_pin->sink_eld;
cancel_delayed_work(&per_pin->work); cancel_delayed_work(&per_pin->work);
...@@ -1749,6 +1756,7 @@ static void generic_hdmi_free(struct hda_codec *codec) ...@@ -1749,6 +1756,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
} }
flush_workqueue(codec->bus->workq); flush_workqueue(codec->bus->workq);
hdmi_array_free(spec);
kfree(spec); kfree(spec);
} }
...@@ -1775,6 +1783,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec, ...@@ -1775,6 +1783,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
/* override pins connection list */ /* override pins connection list */
snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid); snd_printdd("hdmi: haswell: override pin connection 0x%x\n", nid);
nconns = max(spec->num_cvts, 4);
snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids);
} }
...@@ -1855,6 +1864,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) ...@@ -1855,6 +1864,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
return -ENOMEM; return -ENOMEM;
codec->spec = spec; codec->spec = spec;
hdmi_array_init(spec, 4);
snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups); snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
...@@ -1882,24 +1892,30 @@ static int patch_generic_hdmi(struct hda_codec *codec) ...@@ -1882,24 +1892,30 @@ static int patch_generic_hdmi(struct hda_codec *codec)
static int simple_playback_build_pcms(struct hda_codec *codec) static int simple_playback_build_pcms(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hda_pcm *info = spec->pcm_rec; struct hda_pcm *info;
unsigned int chans; unsigned int chans;
struct hda_pcm_stream *pstr; struct hda_pcm_stream *pstr;
struct hdmi_spec_per_cvt *per_cvt;
codec->num_pcms = 1; per_cvt = get_cvt(spec, 0);
codec->pcm_info = info; chans = get_wcaps(codec, per_cvt->cvt_nid);
chans = get_wcaps(codec, spec->cvts[0].cvt_nid);
chans = get_wcaps_channels(chans); chans = get_wcaps_channels(chans);
info->name = get_hdmi_pcm_name(0); info = snd_array_new(&spec->pcm_rec);
if (!info)
return -ENOMEM;
info->name = get_pin(spec, 0)->pcm_name;
sprintf(info->name, "HDMI 0");
info->pcm_type = HDA_PCM_TYPE_HDMI; info->pcm_type = HDA_PCM_TYPE_HDMI;
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
*pstr = spec->pcm_playback; *pstr = spec->pcm_playback;
pstr->nid = spec->cvts[0].cvt_nid; pstr->nid = per_cvt->cvt_nid;
if (pstr->channels_max <= 2 && chans && chans <= 16) if (pstr->channels_max <= 2 && chans && chans <= 16)
pstr->channels_max = chans; pstr->channels_max = chans;
codec->num_pcms = 1;
codec->pcm_info = info;
return 0; return 0;
} }
...@@ -1919,11 +1935,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec, ...@@ -1919,11 +1935,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec,
static int simple_playback_build_controls(struct hda_codec *codec) static int simple_playback_build_controls(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_cvt *per_cvt;
int err; int err;
err = snd_hda_create_spdif_out_ctls(codec, per_cvt = get_cvt(spec, 0);
spec->cvts[0].cvt_nid, err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid,
spec->cvts[0].cvt_nid); per_cvt->cvt_nid);
if (err < 0) if (err < 0)
return err; return err;
return simple_hdmi_build_jack(codec, 0); return simple_hdmi_build_jack(codec, 0);
...@@ -1932,7 +1949,8 @@ static int simple_playback_build_controls(struct hda_codec *codec) ...@@ -1932,7 +1949,8 @@ static int simple_playback_build_controls(struct hda_codec *codec)
static int simple_playback_init(struct hda_codec *codec) static int simple_playback_init(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
hda_nid_t pin = spec->pins[0].pin_nid; struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
hda_nid_t pin = per_pin->pin_nid;
snd_hda_codec_write(codec, pin, 0, snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
...@@ -1948,6 +1966,7 @@ static void simple_playback_free(struct hda_codec *codec) ...@@ -1948,6 +1966,7 @@ static void simple_playback_free(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
hdmi_array_free(spec);
kfree(spec); kfree(spec);
} }
...@@ -2111,20 +2130,29 @@ static int patch_simple_hdmi(struct hda_codec *codec, ...@@ -2111,20 +2130,29 @@ static int patch_simple_hdmi(struct hda_codec *codec,
hda_nid_t cvt_nid, hda_nid_t pin_nid) hda_nid_t cvt_nid, hda_nid_t pin_nid)
{ {
struct hdmi_spec *spec; struct hdmi_spec *spec;
struct hdmi_spec_per_cvt *per_cvt;
struct hdmi_spec_per_pin *per_pin;
spec = kzalloc(sizeof(*spec), GFP_KERNEL); spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (!spec) if (!spec)
return -ENOMEM; return -ENOMEM;
codec->spec = spec; codec->spec = spec;
hdmi_array_init(spec, 1);
spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.num_dacs = 0; /* no analog */
spec->multiout.max_channels = 2; spec->multiout.max_channels = 2;
spec->multiout.dig_out_nid = cvt_nid; spec->multiout.dig_out_nid = cvt_nid;
spec->num_cvts = 1; spec->num_cvts = 1;
spec->num_pins = 1; spec->num_pins = 1;
spec->cvts[0].cvt_nid = cvt_nid; per_pin = snd_array_new(&spec->pins);
spec->pins[0].pin_nid = pin_nid; per_cvt = snd_array_new(&spec->cvts);
if (!per_pin || !per_cvt) {
simple_playback_free(codec);
return -ENOMEM;
}
per_cvt->cvt_nid = cvt_nid;
per_pin->pin_nid = pin_nid;
spec->pcm_playback = simple_pcm_playback; spec->pcm_playback = simple_pcm_playback;
codec->patch_ops = simple_hdmi_patch_ops; codec->patch_ops = simple_hdmi_patch_ops;
...@@ -2201,9 +2229,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -2201,9 +2229,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
int i; int i;
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hda_spdif_out *spdif; struct hda_spdif_out *spdif;
struct hdmi_spec_per_cvt *per_cvt;
mutex_lock(&codec->spdif_mutex); mutex_lock(&codec->spdif_mutex);
spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); per_cvt = get_cvt(spec, 0);
spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
chs = substream->runtime->channels; chs = substream->runtime->channels;
...@@ -2325,13 +2355,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) ...@@ -2325,13 +2355,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
int err = simple_playback_build_pcms(codec); int err = simple_playback_build_pcms(codec);
spec->pcm_rec[0].own_chmap = true; if (!err) {
struct hda_pcm *info = get_pcm_rec(spec, 0);
info->own_chmap = true;
}
return err; return err;
} }
static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hda_pcm *info;
struct snd_pcm_chmap *chmap; struct snd_pcm_chmap *chmap;
int err; int err;
...@@ -2340,7 +2374,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) ...@@ -2340,7 +2374,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
return err; return err;
/* add channel maps */ /* add channel maps */
err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm, info = get_pcm_rec(spec, 0);
err = snd_pcm_add_chmap_ctls(info->pcm,
SNDRV_PCM_STREAM_PLAYBACK, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_alt_chmaps, 8, 0, &chmap); snd_pcm_alt_chmaps, 8, 0, &chmap);
if (err < 0) if (err < 0)
...@@ -2395,6 +2430,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -2395,6 +2430,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream) struct snd_pcm_substream *substream)
{ {
struct hdmi_spec *spec = codec->spec; struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0);
int chans = substream->runtime->channels; int chans = substream->runtime->channels;
int i, err; int i, err;
...@@ -2402,11 +2438,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, ...@@ -2402,11 +2438,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
substream); substream);
if (err < 0) if (err < 0)
return err; return err;
snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
AC_VERB_SET_CVT_CHAN_COUNT, chans - 1); AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
/* FIXME: XXX */ /* FIXME: XXX */
for (i = 0; i < chans; i++) { for (i = 0; i < chans; i++) {
snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
AC_VERB_SET_HDMI_CHAN_SLOT, AC_VERB_SET_HDMI_CHAN_SLOT,
(i << 4) | i); (i << 4) | i);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment