aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2009-10-21 08:48:23 -0400
committerTakashi Iwai <tiwai@suse.de>2009-11-16 05:34:41 -0500
commit123c07aeddd71fbb295842a8c19866e780b9a100 (patch)
tree8b97495608cad55f9169a826fe4637f9ac2d21c3
parentfe705ab1526bc2c8b7756f3a855f040ab2060af2 (diff)
ALSA: hda_intel: Digital PC Beep - change behaviour for input layer
Original implementation was keeping registered input device for SND_BEEP and SND_TONE events all time. This patch changes this behaviour: If digital PC Beep is turned off using universal control switch, the input device is unregistered. Explanation: The kd_mksound() send SND_BEEP and SND_TONE only to last registered device acceping those events. It means that the HDA Intel audio driver blocks also the internal PC Speaker device (pcspkr.c driver) even if the HDA Beep is muted. The user can easy disable all beeps using 'setterm -blength 0' or 'xset b off' command. Signed-off-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_beep.c88
-rw-r--r--sound/pci/hda/hda_beep.h4
-rw-r--r--sound/pci/hda/hda_codec.c12
-rw-r--r--sound/pci/hda/hda_local.h15
-rw-r--r--sound/pci/hda/patch_analog.c2
-rw-r--r--sound/pci/hda/patch_realtek.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c16
7 files changed, 111 insertions, 28 deletions
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 3f51a981e604..0e986537d570 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -113,23 +113,25 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
113 return 0; 113 return 0;
114} 114}
115 115
116int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) 116static void snd_hda_do_detach(struct hda_beep *beep)
117{
118 input_unregister_device(beep->dev);
119 beep->dev = NULL;
120 cancel_work_sync(&beep->beep_work);
121 /* turn off beep for sure */
122 snd_hda_codec_write_cache(beep->codec, beep->nid, 0,
123 AC_VERB_SET_BEEP_CONTROL, 0);
124}
125
126static int snd_hda_do_attach(struct hda_beep *beep)
117{ 127{
118 struct input_dev *input_dev; 128 struct input_dev *input_dev;
119 struct hda_beep *beep; 129 struct hda_codec *codec = beep->codec;
120 int err; 130 int err;
121 131
122 if (!snd_hda_get_bool_hint(codec, "beep"))
123 return 0; /* disabled explicitly */
124
125 beep = kzalloc(sizeof(*beep), GFP_KERNEL);
126 if (beep == NULL)
127 return -ENOMEM;
128 snprintf(beep->phys, sizeof(beep->phys),
129 "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
130 input_dev = input_allocate_device(); 132 input_dev = input_allocate_device();
131 if (!input_dev) { 133 if (!input_dev) {
132 kfree(beep); 134 printk(KERN_INFO "hda_beep: unable to allocate input device\n");
133 return -ENOMEM; 135 return -ENOMEM;
134 } 136 }
135 137
@@ -151,21 +153,71 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
151 err = input_register_device(input_dev); 153 err = input_register_device(input_dev);
152 if (err < 0) { 154 if (err < 0) {
153 input_free_device(input_dev); 155 input_free_device(input_dev);
154 kfree(beep); 156 printk(KERN_INFO "hda_beep: unable to register input device\n");
155 return err; 157 return err;
156 } 158 }
159 beep->dev = input_dev;
160 return 0;
161}
162
163static void snd_hda_do_register(struct work_struct *work)
164{
165 struct hda_beep *beep =
166 container_of(work, struct hda_beep, register_work);
167 int request;
168
169 mutex_lock(&beep->mutex);
170 request = beep->request_enable;
171 if (beep->enabled != request) {
172 if (!request) {
173 snd_hda_do_detach(beep);
174 } else {
175 if (snd_hda_do_attach(beep) < 0)
176 goto __out;
177 }
178 beep->enabled = request;
179 }
180 __out:
181 mutex_unlock(&beep->mutex);
182}
183
184int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
185{
186 struct hda_beep *beep = codec->beep;
187 enable = !!enable;
188 if (beep && beep->enabled != enable) {
189 beep->request_enable = enable;
190 schedule_work(&beep->register_work);
191 return 1;
192 }
193 return 0;
194}
195EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
196
197int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
198{
199 struct hda_beep *beep;
200
201 if (!snd_hda_get_bool_hint(codec, "beep"))
202 return 0; /* disabled explicitly */
157 203
204 beep = kzalloc(sizeof(*beep), GFP_KERNEL);
205 if (beep == NULL)
206 return -ENOMEM;
207 snprintf(beep->phys, sizeof(beep->phys),
208 "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr);
158 /* enable linear scale */ 209 /* enable linear scale */
159 snd_hda_codec_write(codec, nid, 0, 210 snd_hda_codec_write(codec, nid, 0,
160 AC_VERB_SET_DIGI_CONVERT_2, 0x01); 211 AC_VERB_SET_DIGI_CONVERT_2, 0x01);
161 212
162 beep->nid = nid; 213 beep->nid = nid;
163 beep->dev = input_dev;
164 beep->codec = codec; 214 beep->codec = codec;
165 beep->enabled = 1;
166 codec->beep = beep; 215 codec->beep = beep;
167 216
217 INIT_WORK(&beep->register_work, &snd_hda_do_register);
168 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); 218 INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
219 mutex_init(&beep->mutex);
220
169 return 0; 221 return 0;
170} 222}
171EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); 223EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
@@ -174,11 +226,11 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
174{ 226{
175 struct hda_beep *beep = codec->beep; 227 struct hda_beep *beep = codec->beep;
176 if (beep) { 228 if (beep) {
177 cancel_work_sync(&beep->beep_work); 229 cancel_work_sync(&beep->register_work);
178 230 if (beep->enabled)
179 input_unregister_device(beep->dev); 231 snd_hda_do_detach(beep);
180 kfree(beep);
181 codec->beep = NULL; 232 codec->beep = NULL;
233 kfree(beep);
182 } 234 }
183} 235}
184EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); 236EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index 0c3de787c717..68465f679d8c 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -32,11 +32,15 @@ struct hda_beep {
32 int tone; 32 int tone;
33 hda_nid_t nid; 33 hda_nid_t nid;
34 unsigned int enabled:1; 34 unsigned int enabled:1;
35 unsigned int request_enable:1;
35 unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ 36 unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */
37 struct work_struct register_work; /* scheduled task for beep event */
36 struct work_struct beep_work; /* scheduled task for beep event */ 38 struct work_struct beep_work; /* scheduled task for beep event */
39 struct mutex mutex;
37}; 40};
38 41
39#ifdef CONFIG_SND_HDA_INPUT_BEEP 42#ifdef CONFIG_SND_HDA_INPUT_BEEP
43int snd_hda_enable_beep_device(struct hda_codec *codec, int enable);
40int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); 44int snd_hda_attach_beep_device(struct hda_codec *codec, int nid);
41void snd_hda_detach_beep_device(struct hda_codec *codec); 45void snd_hda_detach_beep_device(struct hda_codec *codec);
42#else 46#else
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 444d9039c1ac..7fd2abe1129d 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -30,6 +30,7 @@
30#include <sound/tlv.h> 30#include <sound/tlv.h>
31#include <sound/initval.h> 31#include <sound/initval.h>
32#include "hda_local.h" 32#include "hda_local.h"
33#include "hda_beep.h"
33#include <sound/hda_hwdep.h> 34#include <sound/hda_hwdep.h>
34 35
35/* 36/*
@@ -1734,6 +1735,17 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
1734} 1735}
1735EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); 1736EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
1736 1737
1738int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
1739 struct snd_ctl_elem_value *ucontrol)
1740{
1741 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1742 long *valp = ucontrol->value.integer.value;
1743
1744 snd_hda_enable_beep_device(codec, *valp);
1745 return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
1746}
1747EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);
1748
1737/* 1749/*
1738 * bound volume controls 1750 * bound volume controls
1739 * 1751 *
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index c1ca3182e6a4..3001794ad291 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -66,6 +66,19 @@
66/* stereo mute switch */ 66/* stereo mute switch */
67#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ 67#define HDA_CODEC_MUTE(xname, nid, xindex, direction) \
68 HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) 68 HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction)
69/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */
70#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
71 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
72 .info = snd_hda_mixer_amp_switch_info, \
73 .get = snd_hda_mixer_amp_switch_get, \
74 .put = snd_hda_mixer_amp_switch_put_beep, \
75 .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) }
76/* special beep mono mute switch */
77#define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \
78 HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction)
79/* special beep stereo mute switch */
80#define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \
81 HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction)
69 82
70int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, 83int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
71 struct snd_ctl_elem_info *uinfo); 84 struct snd_ctl_elem_info *uinfo);
@@ -81,6 +94,8 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
81 struct snd_ctl_elem_value *ucontrol); 94 struct snd_ctl_elem_value *ucontrol);
82int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, 95int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
83 struct snd_ctl_elem_value *ucontrol); 96 struct snd_ctl_elem_value *ucontrol);
97int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
98 struct snd_ctl_elem_value *ucontrol);
84/* lowlevel accessor with caching; use carefully */ 99/* lowlevel accessor with caching; use carefully */
85int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, 100int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
86 int direction, int index); 101 int direction, int index);
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 2d603f6aba63..a0293614a0b9 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -159,7 +159,7 @@ static void ad198x_free_kctls(struct hda_codec *codec);
159/* additional beep mixers; the actual parameters are overwritten at build */ 159/* additional beep mixers; the actual parameters are overwritten at build */
160static struct snd_kcontrol_new ad_beep_mixer[] = { 160static struct snd_kcontrol_new ad_beep_mixer[] = {
161 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), 161 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
162 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT), 162 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
163 { } /* end */ 163 { } /* end */
164}; 164};
165 165
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 49de107db16b..8c04e0e0f655 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -2413,7 +2413,7 @@ static void alc_free_kctls(struct hda_codec *codec);
2413/* additional beep mixers; the actual parameters are overwritten at build */ 2413/* additional beep mixers; the actual parameters are overwritten at build */
2414static struct snd_kcontrol_new alc_beep_mixer[] = { 2414static struct snd_kcontrol_new alc_beep_mixer[] = {
2415 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), 2415 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
2416 HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT), 2416 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
2417 { } /* end */ 2417 { } /* end */
2418}; 2418};
2419 2419
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 8d65d2b25234..87ba239ff1c9 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -2648,6 +2648,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol,
2648enum { 2648enum {
2649 STAC_CTL_WIDGET_VOL, 2649 STAC_CTL_WIDGET_VOL,
2650 STAC_CTL_WIDGET_MUTE, 2650 STAC_CTL_WIDGET_MUTE,
2651 STAC_CTL_WIDGET_MUTE_BEEP,
2651 STAC_CTL_WIDGET_MONO_MUX, 2652 STAC_CTL_WIDGET_MONO_MUX,
2652 STAC_CTL_WIDGET_HP_SWITCH, 2653 STAC_CTL_WIDGET_HP_SWITCH,
2653 STAC_CTL_WIDGET_IO_SWITCH, 2654 STAC_CTL_WIDGET_IO_SWITCH,
@@ -2658,6 +2659,7 @@ enum {
2658static struct snd_kcontrol_new stac92xx_control_templates[] = { 2659static struct snd_kcontrol_new stac92xx_control_templates[] = {
2659 HDA_CODEC_VOLUME(NULL, 0, 0, 0), 2660 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2660 HDA_CODEC_MUTE(NULL, 0, 0, 0), 2661 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2662 HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0),
2661 STAC_MONO_MUX, 2663 STAC_MONO_MUX,
2662 STAC_CODEC_HP_SWITCH(NULL), 2664 STAC_CODEC_HP_SWITCH(NULL),
2663 STAC_CODEC_IO_SWITCH(NULL, 0), 2665 STAC_CODEC_IO_SWITCH(NULL, 0),
@@ -3221,11 +3223,14 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec,
3221{ 3223{
3222 struct sigmatel_spec *spec = codec->spec; 3224 struct sigmatel_spec *spec = codec->spec;
3223 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); 3225 u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
3224 int err; 3226 int err, type = STAC_CTL_WIDGET_MUTE_BEEP;
3227
3228 if (spec->anabeep_nid == nid)
3229 type = STAC_CTL_WIDGET_MUTE;
3225 3230
3226 /* check for mute support for the the amp */ 3231 /* check for mute support for the the amp */
3227 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { 3232 if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
3228 err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, 3233 err = stac92xx_add_control(spec, type,
3229 "Beep Playback Switch", 3234 "Beep Playback Switch",
3230 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); 3235 HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT));
3231 if (err < 0) 3236 if (err < 0)
@@ -3258,12 +3263,7 @@ static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
3258 struct snd_ctl_elem_value *ucontrol) 3263 struct snd_ctl_elem_value *ucontrol)
3259{ 3264{
3260 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 3265 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3261 int enabled = !!ucontrol->value.integer.value[0]; 3266 return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
3262 if (codec->beep->enabled != enabled) {
3263 codec->beep->enabled = enabled;
3264 return 1;
3265 }
3266 return 0;
3267} 3267}
3268 3268
3269static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { 3269static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = {