Commit 95c09099 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Avoid call of snd_jack_report at release

Don't call snd_jack_report at release of sigmatel and conexnat codecs
which results in Oops at unloading the module.

The Oops is triggered by the power-up sequence during the free due to
the pincfg restoration.  Since the power-up sequence is involved with
the unsol handling, the jack reporting may be issued during that.
The Oops occurs with this jack reporting because the jack instances
have been already released but the codec doesn't do the proper
book-keeping.

This patch adds the book-keeping of jack instances to avoid the access
to bogus pointers.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 9d59065c
...@@ -350,12 +350,20 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, ...@@ -350,12 +350,20 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
} }
#ifdef CONFIG_SND_JACK #ifdef CONFIG_SND_JACK
static void conexant_free_jack_priv(struct snd_jack *jack)
{
struct conexant_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
static int conexant_add_jack(struct hda_codec *codec, static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type) hda_nid_t nid, int type)
{ {
struct conexant_spec *spec; struct conexant_spec *spec;
struct conexant_jack *jack; struct conexant_jack *jack;
const char *name; const char *name;
int err;
spec = codec->spec; spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32); snd_array_init(&spec->jacks, sizeof(*jack), 32);
...@@ -368,7 +376,12 @@ static int conexant_add_jack(struct hda_codec *codec, ...@@ -368,7 +376,12 @@ static int conexant_add_jack(struct hda_codec *codec,
jack->nid = nid; jack->nid = nid;
jack->type = type; jack->type = type;
return snd_jack_new(codec->bus->card, name, type, &jack->jack); err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0)
return err;
jack->jack->private_data = jack;
jack->jack->private_free = conexant_free_jack_priv;
return 0;
} }
static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
...@@ -455,8 +468,10 @@ static void conexant_free(struct hda_codec *codec) ...@@ -455,8 +468,10 @@ static void conexant_free(struct hda_codec *codec)
if (spec->jacks.list) { if (spec->jacks.list) {
struct conexant_jack *jacks = spec->jacks.list; struct conexant_jack *jacks = spec->jacks.list;
int i; int i;
for (i = 0; i < spec->jacks.used; i++) for (i = 0; i < spec->jacks.used; i++, jacks++) {
snd_device_free(codec->bus->card, &jacks[i].jack); if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
snd_array_free(&spec->jacks); snd_array_free(&spec->jacks);
} }
#endif #endif
......
...@@ -3851,6 +3851,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, ...@@ -3851,6 +3851,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
} }
#ifdef CONFIG_SND_JACK
static void stac92xx_free_jack_priv(struct snd_jack *jack)
{
struct sigmatel_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}
#endif
static int stac92xx_add_jack(struct hda_codec *codec, static int stac92xx_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type) hda_nid_t nid, int type)
{ {
...@@ -3860,6 +3869,7 @@ static int stac92xx_add_jack(struct hda_codec *codec, ...@@ -3860,6 +3869,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
int def_conf = snd_hda_codec_get_pincfg(codec, nid); int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf); int connectivity = get_defcfg_connect(def_conf);
char name[32]; char name[32];
int err;
if (connectivity && connectivity != AC_JACK_PORT_FIXED) if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0; return 0;
...@@ -3876,10 +3886,15 @@ static int stac92xx_add_jack(struct hda_codec *codec, ...@@ -3876,10 +3886,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
snd_hda_get_jack_connectivity(def_conf), snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf)); snd_hda_get_jack_location(def_conf));
return snd_jack_new(codec->bus->card, name, type, &jack->jack); err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
#else if (err < 0) {
return 0; jack->nid = 0;
return err;
}
jack->jack->private_data = jack;
jack->jack->private_free = stac92xx_free_jack_priv;
#endif #endif
return 0;
} }
static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
...@@ -4138,8 +4153,10 @@ static void stac92xx_free_jacks(struct hda_codec *codec) ...@@ -4138,8 +4153,10 @@ static void stac92xx_free_jacks(struct hda_codec *codec)
if (!codec->bus->shutdown && spec->jacks.list) { if (!codec->bus->shutdown && spec->jacks.list) {
struct sigmatel_jack *jacks = spec->jacks.list; struct sigmatel_jack *jacks = spec->jacks.list;
int i; int i;
for (i = 0; i < spec->jacks.used; i++) for (i = 0; i < spec->jacks.used; i++, jacks++) {
snd_device_free(codec->bus->card, &jacks[i].jack); if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
} }
snd_array_free(&spec->jacks); snd_array_free(&spec->jacks);
#endif #endif
......
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