diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-02-28 13:42:09 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-02-28 14:02:21 +0100 |
commit | d604b3990884062873e3bef09ef5e89857c409c3 (patch) | |
tree | 2bb427552257ef1404ac61bb67e212b611fe92ea /sound/pci/hda/hda_beep.c | |
parent | 2b9e4a73fbd90cb8459cf84c12ae05d2eb81da41 (diff) |
ALSA: hda - Fix registration of beep input device
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@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_beep.c')
-rw-r--r-- | sound/pci/hda/hda_beep.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 88bb08486f77..8c6c50afc0b7 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -139,7 +139,10 @@ static void turn_off_beep(struct hda_beep *beep) static void snd_hda_do_detach(struct hda_beep *beep) { - input_unregister_device(beep->dev); + if (beep->registered) + input_unregister_device(beep->dev); + else + input_free_device(beep->dev); beep->dev = NULL; turn_off_beep(beep); } @@ -148,7 +151,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 +171,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 +240,27 @@ 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; + } + beep->registered = true; + 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); |