]> Pileus Git - ~andy/linux/blobdiff - sound/pci/hda/hda_beep.c
ALSA: hda - Avoid possible race of beep on/off
[~andy/linux] / sound / pci / hda / hda_beep.c
index 60738e52b8f9becb3ccd74786a2326748df11cb9..0bc2315b181dad0ec6ed7a33af9e0a0a636c3608 100644 (file)
@@ -162,50 +162,20 @@ static int snd_hda_do_attach(struct hda_beep *beep)
        return 0;
 }
 
-static void snd_hda_do_register(struct work_struct *work)
-{
-       struct hda_beep *beep =
-               container_of(work, struct hda_beep, register_work);
-
-       mutex_lock(&beep->mutex);
-       if (beep->enabled && !beep->dev)
-               snd_hda_do_attach(beep);
-       mutex_unlock(&beep->mutex);
-}
-
-static void snd_hda_do_unregister(struct work_struct *work)
-{
-       struct hda_beep *beep =
-               container_of(work, struct hda_beep, unregister_work.work);
-
-       mutex_lock(&beep->mutex);
-       if (!beep->enabled && beep->dev)
-               snd_hda_do_detach(beep);
-       mutex_unlock(&beep->mutex);
-}
-
 int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
 {
        struct hda_beep *beep = codec->beep;
-       enable = !!enable;
-       if (beep == NULL)
+       if (!beep)
                return 0;
+       enable = !!enable;
        if (beep->enabled != enable) {
                beep->enabled = enable;
                if (!enable) {
+                       cancel_work_sync(&beep->beep_work);
                        /* turn off beep */
                        snd_hda_codec_write(beep->codec, beep->nid, 0,
                                                  AC_VERB_SET_BEEP_CONTROL, 0);
                }
-               if (beep->mode == HDA_BEEP_MODE_SWREG) {
-                       if (enable) {
-                               cancel_delayed_work(&beep->unregister_work);
-                               schedule_work(&beep->register_work);
-                       } else {
-                               schedule_delayed_work(&beep->unregister_work,
-                                                                          HZ);
-                       }
-               }
                return 1;
        }
        return 0;
@@ -215,6 +185,7 @@ EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
 int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 {
        struct hda_beep *beep;
+       int err;
 
        if (!snd_hda_get_bool_hint(codec, "beep"))
                return 0; /* disabled explicitly by hints */
@@ -232,21 +203,16 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
 
        beep->nid = nid;
        beep->codec = codec;
-       beep->mode = codec->beep_mode;
        codec->beep = beep;
 
-       INIT_WORK(&beep->register_work, &snd_hda_do_register);
-       INIT_DELAYED_WORK(&beep->unregister_work, &snd_hda_do_unregister);
        INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
        mutex_init(&beep->mutex);
 
-       if (beep->mode == HDA_BEEP_MODE_ON) {
-               int err = snd_hda_do_attach(beep);
-               if (err < 0) {
-                       kfree(beep);
-                       codec->beep = NULL;
-                       return err;
-               }
+       err = snd_hda_do_attach(beep);
+       if (err < 0) {
+               kfree(beep);
+               codec->beep = NULL;
+               return err;
        }
 
        return 0;
@@ -257,8 +223,6 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 {
        struct hda_beep *beep = codec->beep;
        if (beep) {
-               cancel_work_sync(&beep->register_work);
-               cancel_delayed_work(&beep->unregister_work);
                if (beep->dev)
                        snd_hda_do_detach(beep);
                codec->beep = NULL;
@@ -266,3 +230,31 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
        }
 }
 EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
+
+/* get/put callbacks for beep mute mixer switches */
+int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_beep *beep = codec->beep;
+       if (beep) {
+               ucontrol->value.integer.value[0] =
+                       ucontrol->value.integer.value[1] =
+                       beep->enabled;
+               return 0;
+       }
+       return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
+}
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get_beep);
+
+int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_beep *beep = codec->beep;
+       if (beep)
+               snd_hda_enable_beep_device(codec,
+                                          *ucontrol->value.integer.value);
+       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);