diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-02-28 07:42:09 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-02-28 08:02:21 -0500 |
commit | d604b3990884062873e3bef09ef5e89857c409c3 (patch) | |
tree | 2bb427552257ef1404ac61bb67e212b611fe92ea | |
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>
-rw-r--r-- | sound/pci/hda/hda_beep.c | 33 | ||||
-rw-r--r-- | sound/pci/hda/hda_beep.h | 6 | ||||
-rw-r--r-- | sound/pci/hda/hda_codec.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/hda_generic.c | 1 | ||||
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 4 |
5 files changed, 39 insertions, 13 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) | |||
139 | 139 | ||
140 | static void snd_hda_do_detach(struct hda_beep *beep) | 140 | static void snd_hda_do_detach(struct hda_beep *beep) |
141 | { | 141 | { |
142 | input_unregister_device(beep->dev); | 142 | if (beep->registered) |
143 | input_unregister_device(beep->dev); | ||
144 | else | ||
145 | input_free_device(beep->dev); | ||
143 | beep->dev = NULL; | 146 | beep->dev = NULL; |
144 | turn_off_beep(beep); | 147 | turn_off_beep(beep); |
145 | } | 148 | } |
@@ -148,7 +151,6 @@ static int snd_hda_do_attach(struct hda_beep *beep) | |||
148 | { | 151 | { |
149 | struct input_dev *input_dev; | 152 | struct input_dev *input_dev; |
150 | struct hda_codec *codec = beep->codec; | 153 | struct hda_codec *codec = beep->codec; |
151 | int err; | ||
152 | 154 | ||
153 | input_dev = input_allocate_device(); | 155 | input_dev = input_allocate_device(); |
154 | if (!input_dev) | 156 | if (!input_dev) |
@@ -169,12 +171,6 @@ static int snd_hda_do_attach(struct hda_beep *beep) | |||
169 | input_dev->dev.parent = &codec->dev; | 171 | input_dev->dev.parent = &codec->dev; |
170 | input_set_drvdata(input_dev, beep); | 172 | input_set_drvdata(input_dev, beep); |
171 | 173 | ||
172 | err = input_register_device(input_dev); | ||
173 | if (err < 0) { | ||
174 | input_free_device(input_dev); | ||
175 | codec_err(codec, "hda_beep: unable to register input device\n"); | ||
176 | return err; | ||
177 | } | ||
178 | beep->dev = input_dev; | 174 | beep->dev = input_dev; |
179 | return 0; | 175 | return 0; |
180 | } | 176 | } |
@@ -244,6 +240,27 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) | |||
244 | } | 240 | } |
245 | EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); | 241 | EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); |
246 | 242 | ||
243 | int snd_hda_register_beep_device(struct hda_codec *codec) | ||
244 | { | ||
245 | struct hda_beep *beep = codec->beep; | ||
246 | int err; | ||
247 | |||
248 | if (!beep || !beep->dev) | ||
249 | return 0; | ||
250 | |||
251 | err = input_register_device(beep->dev); | ||
252 | if (err < 0) { | ||
253 | codec_err(codec, "hda_beep: unable to register input device\n"); | ||
254 | input_free_device(beep->dev); | ||
255 | codec->beep = NULL; | ||
256 | kfree(beep); | ||
257 | return err; | ||
258 | } | ||
259 | beep->registered = true; | ||
260 | return 0; | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(snd_hda_register_beep_device); | ||
263 | |||
247 | static bool ctl_has_mute(struct snd_kcontrol *kcontrol) | 264 | static bool ctl_has_mute(struct snd_kcontrol *kcontrol) |
248 | { | 265 | { |
249 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 266 | 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..a63b5e077332 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h | |||
@@ -34,6 +34,7 @@ struct hda_beep { | |||
34 | char phys[32]; | 34 | char phys[32]; |
35 | int tone; | 35 | int tone; |
36 | hda_nid_t nid; | 36 | hda_nid_t nid; |
37 | unsigned int registered:1; | ||
37 | unsigned int enabled:1; | 38 | unsigned int enabled:1; |
38 | unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ | 39 | unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ |
39 | unsigned int playing:1; | 40 | unsigned int playing:1; |
@@ -45,6 +46,7 @@ struct hda_beep { | |||
45 | int snd_hda_enable_beep_device(struct hda_codec *codec, int enable); | 46 | int snd_hda_enable_beep_device(struct hda_codec *codec, int enable); |
46 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); | 47 | int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); |
47 | void snd_hda_detach_beep_device(struct hda_codec *codec); | 48 | void snd_hda_detach_beep_device(struct hda_codec *codec); |
49 | int snd_hda_register_beep_device(struct hda_codec *codec); | ||
48 | #else | 50 | #else |
49 | static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | 51 | static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) |
50 | { | 52 | { |
@@ -53,5 +55,9 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) | |||
53 | static inline void snd_hda_detach_beep_device(struct hda_codec *codec) | 55 | static inline void snd_hda_detach_beep_device(struct hda_codec *codec) |
54 | { | 56 | { |
55 | } | 57 | } |
58 | static inline int snd_hda_register_beep_device(struct hda_codec *codec) | ||
59 | { | ||
60 | return 0; | ||
61 | } | ||
56 | #endif | 62 | #endif |
57 | #endif | 63 | #endif |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 6db2dbcbf4d3..4c20277a6835 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, | |||
1379 | static int snd_hda_codec_dev_register(struct snd_device *device) | 1379 | static int snd_hda_codec_dev_register(struct snd_device *device) |
1380 | { | 1380 | { |
1381 | struct hda_codec *codec = device->device_data; | 1381 | struct hda_codec *codec = device->device_data; |
1382 | int err = device_add(&codec->dev); | ||
1382 | 1383 | ||
1383 | return device_add(&codec->dev); | 1384 | if (err < 0) |
1385 | return err; | ||
1386 | snd_hda_register_beep_device(codec); | ||
1387 | return 0; | ||
1384 | } | 1388 | } |
1385 | 1389 | ||
1386 | static int snd_hda_codec_dev_disconnect(struct snd_device *device) | 1390 | static int snd_hda_codec_dev_disconnect(struct snd_device *device) |
1387 | { | 1391 | { |
1388 | struct hda_codec *codec = device->device_data; | 1392 | struct hda_codec *codec = device->device_data; |
1389 | 1393 | ||
1394 | snd_hda_detach_beep_device(codec); | ||
1390 | device_del(&codec->dev); | 1395 | device_del(&codec->dev); |
1391 | return 0; | 1396 | return 0; |
1392 | } | 1397 | } |
@@ -2692,6 +2697,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) | |||
2692 | bus->pcm_dev_bits); | 2697 | bus->pcm_dev_bits); |
2693 | } | 2698 | } |
2694 | } | 2699 | } |
2700 | snd_hda_detach_beep_device(codec); | ||
2695 | if (codec->patch_ops.free) | 2701 | if (codec->patch_ops.free) |
2696 | codec->patch_ops.free(codec); | 2702 | codec->patch_ops.free(codec); |
2697 | memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); | 2703 | memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); |
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); | |||
5350 | void snd_hda_gen_free(struct hda_codec *codec) | 5350 | void snd_hda_gen_free(struct hda_codec *codec) |
5351 | { | 5351 | { |
5352 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); | 5352 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); |
5353 | snd_hda_detach_beep_device(codec); | ||
5354 | snd_hda_gen_spec_free(codec->spec); | 5353 | snd_hda_gen_spec_free(codec->spec); |
5355 | kfree(codec->spec); | 5354 | kfree(codec->spec); |
5356 | codec->spec = NULL; | 5355 | 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) | |||
445 | 445 | ||
446 | static void conexant_free(struct hda_codec *codec) | 446 | static void conexant_free(struct hda_codec *codec) |
447 | { | 447 | { |
448 | struct conexant_spec *spec = codec->spec; | 448 | kfree(codec->spec); |
449 | snd_hda_detach_beep_device(codec); | ||
450 | kfree(spec); | ||
451 | } | 449 | } |
452 | 450 | ||
453 | static const struct snd_kcontrol_new cxt_capture_mixers[] = { | 451 | static const struct snd_kcontrol_new cxt_capture_mixers[] = { |