[alsa-devel] [PATCH] ALSA: hda - Fix registration of beep input device
Takashi Iwai
tiwai at suse.de
Fri Feb 28 13:46:34 CET 2014
The beep input device is registered via input_register_device(), but
this is called in snd_hda_attach_beep_device() where the sound devices
aren't registered yet. This leads to the binding to non-existing
object, thus results in failure. And, even if the binding worked
(against the PCI object), it's still racy; the input device appears
before the sound objects.
For fixing this, register the input device properly at dev_register
ops of the codec object it's bound with. Also, call
snd_hda_detach_beep_device() at dev_disconnection so that it's
detached at the right timing. As a bonus, since it's called in the
codec's ops, we can get rid of the further call from the other codec
drivers.
Signed-off-by: Takashi Iwai <tiwai at suse.de>
---
sound/pci/hda/hda_beep.c | 27 ++++++++++++++++++++-------
sound/pci/hda/hda_beep.h | 5 +++++
sound/pci/hda/hda_codec.c | 7 ++++++-
sound/pci/hda/hda_generic.c | 1 -
sound/pci/hda/patch_conexant.c | 4 +---
5 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 88bb08486f77..b9d3d0cd75c9 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -148,7 +148,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
{
struct input_dev *input_dev;
struct hda_codec *codec = beep->codec;
- int err;
input_dev = input_allocate_device();
if (!input_dev)
@@ -169,12 +168,6 @@ static int snd_hda_do_attach(struct hda_beep *beep)
input_dev->dev.parent = &codec->dev;
input_set_drvdata(input_dev, beep);
- err = input_register_device(input_dev);
- if (err < 0) {
- input_free_device(input_dev);
- codec_err(codec, "hda_beep: unable to register input device\n");
- return err;
- }
beep->dev = input_dev;
return 0;
}
@@ -244,6 +237,26 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
+int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+ struct hda_beep *beep = codec->beep;
+ int err;
+
+ if (!beep || !beep->dev)
+ return 0;
+
+ err = input_register_device(beep->dev);
+ if (err < 0) {
+ codec_err(codec, "hda_beep: unable to register input device\n");
+ input_free_device(beep->dev);
+ codec->beep = NULL;
+ kfree(beep);
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_register_beep_device);
+
static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index cb88464676b6..76eb8589fb9e 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -45,6 +45,7 @@ struct hda_beep {
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
void snd_hda_detach_beep_device(struct hda_codec *codec);
+int snd_hda_register_beep_device(struct hda_codec *codec);
#else
static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
{
@@ -53,5 +54,9 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
static inline void snd_hda_detach_beep_device(struct hda_codec *codec)
{
}
+static inline int snd_hda_register_beep_device(struct hda_codec *codec)
+{
+ return 0;
+}
#endif
#endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 6db2dbcbf4d3..555e8c771cfd 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1379,14 +1379,19 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
static int snd_hda_codec_dev_register(struct snd_device *device)
{
struct hda_codec *codec = device->device_data;
+ int err = device_add(&codec->dev);
- return device_add(&codec->dev);
+ if (err < 0)
+ return err;
+ snd_hda_register_beep_device(codec);
+ return 0;
}
static int snd_hda_codec_dev_disconnect(struct snd_device *device)
{
struct hda_codec *codec = device->device_data;
+ snd_hda_detach_beep_device(codec);
device_del(&codec->dev);
return 0;
}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 9e0609a4b2ba..16133881e967 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -5350,7 +5350,6 @@ EXPORT_SYMBOL_GPL(snd_hda_gen_init);
void snd_hda_gen_free(struct hda_codec *codec)
{
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
- snd_hda_detach_beep_device(codec);
snd_hda_gen_spec_free(codec->spec);
kfree(codec->spec);
codec->spec = NULL;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 09d6d0db2b06..1dc7e974f3b1 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -445,9 +445,7 @@ static int conexant_init(struct hda_codec *codec)
static void conexant_free(struct hda_codec *codec)
{
- struct conexant_spec *spec = codec->spec;
- snd_hda_detach_beep_device(codec);
- kfree(spec);
+ kfree(codec->spec);
}
static const struct snd_kcontrol_new cxt_capture_mixers[] = {
--
1.9.0
More information about the Alsa-devel
mailing list