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: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
9d59065cd6
commit
95c0909961
|
@ -350,12 +350,20 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
|
||||
#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,
|
||||
hda_nid_t nid, int type)
|
||||
{
|
||||
struct conexant_spec *spec;
|
||||
struct conexant_jack *jack;
|
||||
const char *name;
|
||||
int err;
|
||||
|
||||
spec = codec->spec;
|
||||
snd_array_init(&spec->jacks, sizeof(*jack), 32);
|
||||
|
@ -368,7 +376,12 @@ static int conexant_add_jack(struct hda_codec *codec,
|
|||
jack->nid = nid;
|
||||
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)
|
||||
|
@ -455,8 +468,10 @@ static void conexant_free(struct hda_codec *codec)
|
|||
if (spec->jacks.list) {
|
||||
struct conexant_jack *jacks = spec->jacks.list;
|
||||
int i;
|
||||
for (i = 0; i < spec->jacks.used; i++)
|
||||
snd_device_free(codec->bus->card, &jacks[i].jack);
|
||||
for (i = 0; i < spec->jacks.used; i++, jacks++) {
|
||||
if (jacks->jack)
|
||||
snd_device_free(codec->bus->card, jacks->jack);
|
||||
}
|
||||
snd_array_free(&spec->jacks);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3851,6 +3851,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
|
|||
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,
|
||||
hda_nid_t nid, int type)
|
||||
{
|
||||
|
@ -3860,6 +3869,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
|
|||
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
|
||||
int connectivity = get_defcfg_connect(def_conf);
|
||||
char name[32];
|
||||
int err;
|
||||
|
||||
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
|
||||
return 0;
|
||||
|
@ -3876,10 +3886,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
|
|||
snd_hda_get_jack_connectivity(def_conf),
|
||||
snd_hda_get_jack_location(def_conf));
|
||||
|
||||
return snd_jack_new(codec->bus->card, name, type, &jack->jack);
|
||||
#else
|
||||
return 0;
|
||||
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
|
||||
if (err < 0) {
|
||||
jack->nid = 0;
|
||||
return err;
|
||||
}
|
||||
jack->jack->private_data = jack;
|
||||
jack->jack->private_free = stac92xx_free_jack_priv;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
|||
if (!codec->bus->shutdown && spec->jacks.list) {
|
||||
struct sigmatel_jack *jacks = spec->jacks.list;
|
||||
int i;
|
||||
for (i = 0; i < spec->jacks.used; i++)
|
||||
snd_device_free(codec->bus->card, &jacks[i].jack);
|
||||
for (i = 0; i < spec->jacks.used; i++, jacks++) {
|
||||
if (jacks->jack)
|
||||
snd_device_free(codec->bus->card, jacks->jack);
|
||||
}
|
||||
}
|
||||
snd_array_free(&spec->jacks);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue