[alsa-devel] [PATCH 1/3] ALSA: hda - Drop explicit memset() by reallocation with __GFP_ZERO
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_codec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 04b5738..a1c5053 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5539,10 +5539,9 @@ void *snd_array_new(struct snd_array *array) void *nlist; if (snd_BUG_ON(num >= 4096)) return NULL; - nlist = krealloc(array->list, size, GFP_KERNEL); + nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO); if (!nlist) return NULL; - memset(nlist + oldsize, 0, size - oldsize); array->list = nlist; array->alloced = num; }
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: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_hdmi.c | 198 ++++++++++++++++++++++++++------------------- 1 file changed, 117 insertions(+), 81 deletions(-)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 78e1827..3e1159d 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -44,16 +44,6 @@ static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); 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 { hda_nid_t cvt_nid; int assigned; @@ -80,16 +70,17 @@ struct hdmi_spec_per_pin { bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ + char pcm_name[8]; /* filled in build_pcm callbacks */ };
struct hdmi_spec { int num_cvts; - struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; - hda_nid_t cvt_nids[MAX_HDMI_CVTS]; + struct snd_array cvts; /* struct hdmi_spec_per_cvt */ + hda_nid_t cvt_nids[4]; /* only for haswell fix */
int num_pins; - struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; - struct hda_pcm pcm_rec[MAX_HDMI_PINS]; + struct snd_array pins; /* struct hdmi_spec_per_pin */ + struct snd_array pcm_rec; /* struct hda_pcm */ unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld; @@ -304,12 +295,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { * 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) { int 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;
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, int 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;
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) int 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;
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, uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
pin_idx = kcontrol->private_value; - eld = &spec->pins[pin_idx].sink_eld; + eld = &get_pin(spec, pin_idx)->sink_eld;
mutex_lock(&eld->lock); uinfo->count = eld->eld_valid ? eld->eld_size : 0; @@ -370,7 +368,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, int pin_idx;
pin_idx = kcontrol->private_value; - eld = &spec->pins[pin_idx].sink_eld; + eld = &get_pin(spec, pin_idx)->sink_eld;
mutex_lock(&eld->lock); 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, kctl->private_value = pin_idx; 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) return err;
- spec->pins[pin_idx].eld_ctl = kctl; + get_pin(spec, pin_idx)->eld_ctl = kctl; return 0; }
@@ -875,14 +873,14 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, struct snd_pcm_substream *substream) { 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; int channels = substream->runtime->channels; struct hdmi_eld *eld; int ca; union audio_infoframe ai;
- eld = &spec->pins[pin_idx].sink_eld; + eld = &per_pin->sink_eld; if (!eld->monitor_present) return;
@@ -977,7 +975,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) if (pin_idx < 0) return;
- hdmi_present_sense(&spec->pins[pin_idx], 1); + hdmi_present_sense(get_pin(spec, pin_idx), 1); snd_hda_jack_report_sync(codec); }
@@ -1083,12 +1081,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; + per_pin = get_pin(spec, pin_idx); eld = &per_pin->sink_eld;
/* Dynamically assign converter to stream */ 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 */ if (per_cvt->assigned) @@ -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) { 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;
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) if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) return 0;
- if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS)) - return -E2BIG; - if (codec->vendor_id == 0x80862807) intel_haswell_fixup_connect_list(codec, pin_nid);
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->non_pcm = false; @@ -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) { struct hdmi_spec *spec = codec->spec; - int cvt_idx; struct hdmi_spec_per_cvt *per_cvt; unsigned int chans; int err;
- if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) - return -E2BIG; - chans = get_wcaps(codec, cvt_nid); chans = get_wcaps_channels(chans);
- cvt_idx = spec->num_cvts; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = snd_array_new(&spec->cvts); + if (!per_cvt) + return -ENOMEM;
per_cvt->cvt_nid = cvt_nid; per_cvt->channels_min = 2; @@ -1328,7 +1322,9 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) if (err < 0) 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; } @@ -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) { struct hda_spdif_out *spdif; @@ -1417,7 +1406,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hda_nid_t cvt_nid = hinfo->nid; struct hdmi_spec *spec = codec->spec; 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;
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); @@ -1450,7 +1439,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); if (snd_BUG_ON(cvt_idx < 0)) return -EINVAL; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = get_cvt(spec, cvt_idx);
snd_BUG_ON(!per_cvt->assigned); per_cvt->assigned = 0; @@ -1459,7 +1448,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, pin_idx = hinfo_to_pin_index(spec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; + per_pin = get_pin(spec, pin_idx);
snd_hda_spdif_ctls_unassign(codec, pin_idx); per_pin->chmap_set = false; @@ -1553,7 +1542,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; 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;
for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) @@ -1568,7 +1557,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; 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; struct snd_pcm_substream *substream; unsigned char chmap[8]; @@ -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++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; - - info = &spec->pcm_rec[pin_idx]; - info->name = get_hdmi_pcm_name(pin_idx); + struct hdmi_spec_per_pin *per_pin; + + 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->own_chmap = true;
@@ -1626,7 +1620,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) }
codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec; + codec->pcm_info = spec->pcm_rec.list;
return 0; } @@ -1635,8 +1629,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) { char hdmi_str[32] = "HDMI/DP"; struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - int pcmdev = spec->pcm_rec[pin_idx].device; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + int pcmdev = get_pcm_rec(spec, pin_idx)->device;
if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); @@ -1654,7 +1648,7 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) int 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); if (err < 0) @@ -1669,9 +1663,8 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) snd_hda_spdif_ctls_unassign(codec, pin_idx);
/* add control for ELD Bytes */ - err = hdmi_create_eld_ctl(codec, - pin_idx, - spec->pcm_rec[pin_idx].device); + err = hdmi_create_eld_ctl(codec, pin_idx, + get_pcm_rec(spec, pin_idx)->device);
if (err < 0) return err; @@ -1709,7 +1702,7 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) int 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;
per_pin->codec = codec; @@ -1726,7 +1719,7 @@ static int generic_hdmi_init(struct hda_codec *codec) int 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;
hdmi_init_pin(codec, pin_nid); @@ -1735,13 +1728,27 @@ static int generic_hdmi_init(struct hda_codec *codec) 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) { struct hdmi_spec *spec = codec->spec; int 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;
cancel_delayed_work(&per_pin->work); @@ -1749,6 +1756,7 @@ static void generic_hdmi_free(struct hda_codec *codec) }
flush_workqueue(codec->bus->workq); + hdmi_array_free(spec); kfree(spec); }
@@ -1775,6 +1783,7 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
/* override pins connection list */ 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); }
@@ -1855,6 +1864,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) return -ENOMEM;
codec->spec = spec; + hdmi_array_init(spec, 4);
snd_hda_pick_fixup(codec, hdmi_models, hdmi_fixup_tbl, hdmi_fixups); snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); @@ -1882,24 +1892,30 @@ static int patch_generic_hdmi(struct hda_codec *codec) static int simple_playback_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct hda_pcm *info; unsigned int chans; struct hda_pcm_stream *pstr; + struct hdmi_spec_per_cvt *per_cvt;
- codec->num_pcms = 1; - codec->pcm_info = info; - - chans = get_wcaps(codec, spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + chans = get_wcaps(codec, per_cvt->cvt_nid); 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; pstr = &info->stream[SNDRV_PCM_STREAM_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) pstr->channels_max = chans;
+ codec->num_pcms = 1; + codec->pcm_info = info; + return 0; }
@@ -1919,11 +1935,12 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec, static int simple_playback_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; int err;
- err = snd_hda_create_spdif_out_ctls(codec, - spec->cvts[0].cvt_nid, - spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid, + per_cvt->cvt_nid); if (err < 0) return err; return simple_hdmi_build_jack(codec, 0); @@ -1932,7 +1949,8 @@ static int simple_playback_build_controls(struct hda_codec *codec) static int simple_playback_init(struct hda_codec *codec) { 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, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); @@ -1948,6 +1966,7 @@ static void simple_playback_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec;
+ hdmi_array_free(spec); kfree(spec); }
@@ -2111,20 +2130,29 @@ static int patch_simple_hdmi(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid) { struct hdmi_spec *spec; + struct hdmi_spec_per_cvt *per_cvt; + struct hdmi_spec_per_pin *per_pin;
spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM;
codec->spec = spec; + hdmi_array_init(spec, 1);
spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = cvt_nid; spec->num_cvts = 1; spec->num_pins = 1; - spec->cvts[0].cvt_nid = cvt_nid; - spec->pins[0].pin_nid = pin_nid; + per_pin = snd_array_new(&spec->pins); + 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;
codec->patch_ops = simple_hdmi_patch_ops; @@ -2201,9 +2229,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, int i; struct hdmi_spec *spec = codec->spec; struct hda_spdif_out *spdif; + struct hdmi_spec_per_cvt *per_cvt;
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;
@@ -2325,13 +2355,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; 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; }
static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info; struct snd_pcm_chmap *chmap; int err;
@@ -2340,7 +2374,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) return err;
/* 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, snd_pcm_alt_chmaps, 8, 0, &chmap); if (err < 0) @@ -2395,6 +2430,7 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0); int chans = substream->runtime->channels; int i, err;
@@ -2402,11 +2438,11 @@ static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, substream); if (err < 0) 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); /* FIXME: XXX */ 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, (i << 4) | i); }
So far, the driver doesn't power down the widget at going down to D3 when the widget node has an EAPD capability and EAPD is actually set on all codecs unless codec->power_filter is set explicitly. This caused a problem on some Conexant codecs, leading to click noises, and we set it as NULL there. But it is very unlikely that the problem hits only these codecs.
Looking back at the development history, this workaround for EAPD was introduced just for some laptops with STAC9200 codec, then we applied it blindly for all. Now, since it's revealed to have an ill effect, we should disable this workaround per default and apply only for the known requiring systems.
The EAPD workaround is implemented now as snd_hda_codec_eapd_power_filter(), and this has to be set explicitly by the codec driver when needed. As of now, only patch_stac9200() sets this one.
Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_codec.c | 13 ++++++------- sound/pci/hda/hda_local.h | 4 ++++ sound/pci/hda/patch_conexant.c | 1 - sound/pci/hda/patch_sigmatel.c | 1 + 4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index a1c5053..8cca987 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1296,8 +1296,6 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec,
static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); -static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, - unsigned int power_state);
/** * snd_hda_codec_new - create a HDA codec @@ -1418,7 +1416,6 @@ int snd_hda_codec_new(struct hda_bus *bus, #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); - codec->power_filter = default_power_filter;
/* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -3759,8 +3756,9 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, }
/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ -static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, - unsigned int power_state) +unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) { if (power_state == AC_PWRST_D3 && get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN && @@ -3772,6 +3770,7 @@ static unsigned int default_power_filter(struct hda_codec *codec, hda_nid_t nid, } return power_state; } +EXPORT_SYMBOL_HDA(snd_hda_codec_eapd_power_filter);
/* * set power state of the codec, and return the power state @@ -3816,8 +3815,8 @@ static void sync_power_up_states(struct hda_codec *codec) hda_nid_t nid = codec->start_nid; int i;
- /* don't care if no or standard filter is used */ - if (!codec->power_filter || codec->power_filter == default_power_filter) + /* don't care if no filter is used */ + if (!codec->power_filter) return;
for (i = 0; i < codec->num_nodes; i++, nid++) { diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 83b7486..e0bf753 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -670,6 +670,10 @@ snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, return (state != target_state); }
+unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state); + /* * AMP control callbacks */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 941bf6c..7d941ef 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -3350,7 +3350,6 @@ static int patch_conexant_auto(struct hda_codec *codec) switch (codec->vendor_id) { case 0x14f15045: codec->single_adc_amp = 1; - codec->power_filter = NULL; /* Needs speaker amp to D3 to avoid click */ break; case 0x14f15047: codec->pin_amp_workaround = 1; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 83d5335..d57c81e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3774,6 +3774,7 @@ static int patch_stac9200(struct hda_codec *codec) spec->gen.own_eapd_ctl = 1;
codec->patch_ops = stac_patch_ops; + codec->power_filter = snd_hda_codec_eapd_power_filter;
snd_hda_add_verbs(codec, stac9200_eapd_init);
participants (1)
-
Takashi Iwai