diff options
-rw-r--r-- | include/sound/control.h | 8 | ||||
-rw-r--r-- | sound/core/Kconfig | 3 | ||||
-rw-r--r-- | sound/core/Makefile | 1 | ||||
-rw-r--r-- | sound/core/ctljack.c | 55 | ||||
-rw-r--r-- | sound/pci/hda/Kconfig | 1 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.c | 56 | ||||
-rw-r--r-- | sound/pci/hda/hda_jack.h | 1 |
7 files changed, 76 insertions, 49 deletions
diff --git a/include/sound/control.h b/include/sound/control.h index 1a94a216ed99..b2796e83c7ac 100644 --- a/include/sound/control.h +++ b/include/sound/control.h | |||
@@ -227,4 +227,12 @@ snd_ctl_add_slave_uncached(struct snd_kcontrol *master, | |||
227 | return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); | 227 | return _snd_ctl_add_slave(master, slave, SND_CTL_SLAVE_NEED_UPDATE); |
228 | } | 228 | } |
229 | 229 | ||
230 | /* | ||
231 | * Helper functions for jack-detection controls | ||
232 | */ | ||
233 | struct snd_kcontrol * | ||
234 | snd_kctl_jack_new(const char *name, int idx, void *private_data); | ||
235 | void snd_kctl_jack_report(struct snd_card *card, | ||
236 | struct snd_kcontrol *kctl, bool status); | ||
237 | |||
230 | #endif /* __SOUND_CONTROL_H */ | 238 | #endif /* __SOUND_CONTROL_H */ |
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 475455c76610..66f287f2f759 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -207,6 +207,9 @@ config SND_PCM_XRUN_DEBUG | |||
207 | config SND_VMASTER | 207 | config SND_VMASTER |
208 | bool | 208 | bool |
209 | 209 | ||
210 | config SND_KCTL_JACK | ||
211 | bool | ||
212 | |||
210 | config SND_DMA_SGBUF | 213 | config SND_DMA_SGBUF |
211 | def_bool y | 214 | def_bool y |
212 | depends on X86 | 215 | depends on X86 |
diff --git a/sound/core/Makefile b/sound/core/Makefile index 350a08d277f4..b4637c3e776e 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -7,6 +7,7 @@ snd-y := sound.o init.o memory.o info.o control.o misc.o device.o | |||
7 | snd-$(CONFIG_ISA_DMA_API) += isadma.o | 7 | snd-$(CONFIG_ISA_DMA_API) += isadma.o |
8 | snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o | 8 | snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o |
9 | snd-$(CONFIG_SND_VMASTER) += vmaster.o | 9 | snd-$(CONFIG_SND_VMASTER) += vmaster.o |
10 | snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o | ||
10 | snd-$(CONFIG_SND_JACK) += jack.o | 11 | snd-$(CONFIG_SND_JACK) += jack.o |
11 | 12 | ||
12 | snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ | 13 | snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ |
diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c new file mode 100644 index 000000000000..af0e78a3809c --- /dev/null +++ b/sound/core/ctljack.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * Helper functions for jack-detection kcontrols | ||
3 | * | ||
4 | * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation; either version 2 of the License, or (at your option) | ||
9 | * any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/control.h> | ||
15 | |||
16 | #define jack_detect_kctl_info snd_ctl_boolean_mono_info | ||
17 | |||
18 | static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, | ||
19 | struct snd_ctl_elem_value *ucontrol) | ||
20 | { | ||
21 | ucontrol->value.integer.value[0] = kcontrol->private_value; | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | static struct snd_kcontrol_new jack_detect_kctl = { | ||
26 | /* name is filled later */ | ||
27 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | ||
28 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
29 | .info = jack_detect_kctl_info, | ||
30 | .get = jack_detect_kctl_get, | ||
31 | }; | ||
32 | |||
33 | struct snd_kcontrol * | ||
34 | snd_kctl_jack_new(const char *name, int idx, void *private_data) | ||
35 | { | ||
36 | struct snd_kcontrol *kctl; | ||
37 | kctl = snd_ctl_new1(&jack_detect_kctl, private_data); | ||
38 | if (!kctl) | ||
39 | return NULL; | ||
40 | snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name); | ||
41 | kctl->id.index = idx; | ||
42 | kctl->private_value = 0; | ||
43 | return kctl; | ||
44 | } | ||
45 | EXPORT_SYMBOL_GPL(snd_kctl_jack_new); | ||
46 | |||
47 | void snd_kctl_jack_report(struct snd_card *card, | ||
48 | struct snd_kcontrol *kctl, bool status) | ||
49 | { | ||
50 | if (kctl->private_value == status) | ||
51 | return; | ||
52 | kctl->private_value = status; | ||
53 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(snd_kctl_jack_report); | ||
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index bb7e102d6726..163b6b5de3eb 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -2,6 +2,7 @@ menuconfig SND_HDA_INTEL | |||
2 | tristate "Intel HD Audio" | 2 | tristate "Intel HD Audio" |
3 | select SND_PCM | 3 | select SND_PCM |
4 | select SND_VMASTER | 4 | select SND_VMASTER |
5 | select SND_KCTL_JACK | ||
5 | help | 6 | help |
6 | Say Y here to include support for Intel "High Definition | 7 | Say Y here to include support for Intel "High Definition |
7 | Audio" (Azalia) and its compatible devices. | 8 | Audio" (Azalia) and its compatible devices. |
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 8829d5c83fec..a2ab52b27265 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c | |||
@@ -97,12 +97,8 @@ static void jack_detect_update(struct hda_codec *codec, | |||
97 | struct hda_jack_tbl *jack) | 97 | struct hda_jack_tbl *jack) |
98 | { | 98 | { |
99 | if (jack->jack_dirty || !jack->jack_detect) { | 99 | if (jack->jack_dirty || !jack->jack_detect) { |
100 | unsigned int val = read_pin_sense(codec, jack->nid); | 100 | jack->pin_sense = read_pin_sense(codec, jack->nid); |
101 | jack->jack_dirty = 0; | 101 | jack->jack_dirty = 0; |
102 | if (val != jack->pin_sense) { | ||
103 | jack->need_notify = 1; | ||
104 | jack->pin_sense = val; | ||
105 | } | ||
106 | } | 102 | } |
107 | } | 103 | } |
108 | 104 | ||
@@ -142,6 +138,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) | |||
142 | } | 138 | } |
143 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); | 139 | EXPORT_SYMBOL_HDA(snd_hda_pin_sense); |
144 | 140 | ||
141 | #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) | ||
142 | |||
145 | /** | 143 | /** |
146 | * snd_hda_jack_detect - query pin Presence Detect status | 144 | * snd_hda_jack_detect - query pin Presence Detect status |
147 | * @codec: the CODEC to sense | 145 | * @codec: the CODEC to sense |
@@ -152,7 +150,7 @@ EXPORT_SYMBOL_HDA(snd_hda_pin_sense); | |||
152 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) | 150 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) |
153 | { | 151 | { |
154 | u32 sense = snd_hda_pin_sense(codec, nid); | 152 | u32 sense = snd_hda_pin_sense(codec, nid); |
155 | return !!(sense & AC_PINSENSE_PRESENCE); | 153 | return get_jack_plug_state(sense); |
156 | } | 154 | } |
157 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect); | 155 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect); |
158 | 156 | ||
@@ -176,58 +174,23 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, | |||
176 | } | 174 | } |
177 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); | 175 | EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); |
178 | 176 | ||
179 | /* queue the notification when needed */ | ||
180 | static void jack_detect_report(struct hda_codec *codec, | ||
181 | struct hda_jack_tbl *jack) | ||
182 | { | ||
183 | jack_detect_update(codec, jack); | ||
184 | if (jack->need_notify) { | ||
185 | snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
186 | &jack->kctl->id); | ||
187 | jack->need_notify = 0; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | /** | 177 | /** |
192 | * snd_hda_jack_report_sync - sync the states of all jacks and report if changed | 178 | * snd_hda_jack_report_sync - sync the states of all jacks and report if changed |
193 | */ | 179 | */ |
194 | void snd_hda_jack_report_sync(struct hda_codec *codec) | 180 | void snd_hda_jack_report_sync(struct hda_codec *codec) |
195 | { | 181 | { |
196 | struct hda_jack_tbl *jack = codec->jacktbl.list; | 182 | struct hda_jack_tbl *jack = codec->jacktbl.list; |
197 | int i; | 183 | int i, state; |
198 | 184 | ||
199 | for (i = 0; i < codec->jacktbl.used; i++, jack++) | 185 | for (i = 0; i < codec->jacktbl.used; i++, jack++) |
200 | if (jack->nid) { | 186 | if (jack->nid) { |
201 | jack_detect_update(codec, jack); | 187 | jack_detect_update(codec, jack); |
202 | jack_detect_report(codec, jack); | 188 | state = get_jack_plug_state(jack->pin_sense); |
189 | snd_kctl_jack_notify(codec->bus->card, jack->kctl, state); | ||
203 | } | 190 | } |
204 | } | 191 | } |
205 | EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync); | 192 | EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync); |
206 | 193 | ||
207 | /* | ||
208 | * jack-detection kcontrols | ||
209 | */ | ||
210 | |||
211 | #define jack_detect_kctl_info snd_ctl_boolean_mono_info | ||
212 | |||
213 | static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, | ||
214 | struct snd_ctl_elem_value *ucontrol) | ||
215 | { | ||
216 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
217 | hda_nid_t nid = kcontrol->private_value; | ||
218 | |||
219 | ucontrol->value.integer.value[0] = snd_hda_jack_detect(codec, nid); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static struct snd_kcontrol_new jack_detect_kctl = { | ||
224 | /* name is filled later */ | ||
225 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | ||
226 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
227 | .info = jack_detect_kctl_info, | ||
228 | .get = jack_detect_kctl_get, | ||
229 | }; | ||
230 | |||
231 | /** | 194 | /** |
232 | * snd_hda_jack_add_kctl - Add a kctl for the given pin | 195 | * snd_hda_jack_add_kctl - Add a kctl for the given pin |
233 | * | 196 | * |
@@ -245,12 +208,9 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, | |||
245 | return 0; | 208 | return 0; |
246 | if (jack->kctl) | 209 | if (jack->kctl) |
247 | return 0; /* already created */ | 210 | return 0; /* already created */ |
248 | kctl = snd_ctl_new1(&jack_detect_kctl, codec); | 211 | kctl = snd_kctl_jack_new(name, idx, codec); |
249 | if (!kctl) | 212 | if (!kctl) |
250 | return -ENOMEM; | 213 | return -ENOMEM; |
251 | snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name); | ||
252 | kctl->id.index = idx; | ||
253 | kctl->private_value = nid; | ||
254 | if (snd_hda_ctl_add(codec, nid, kctl) < 0) | 214 | if (snd_hda_ctl_add(codec, nid, kctl) < 0) |
255 | return -ENOMEM; | 215 | return -ENOMEM; |
256 | jack->kctl = kctl; | 216 | jack->kctl = kctl; |
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index 69a67f8e4f45..4bb75ee16b56 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h | |||
@@ -21,7 +21,6 @@ struct hda_jack_tbl { | |||
21 | unsigned int pin_sense; /* cached pin-sense value */ | 21 | unsigned int pin_sense; /* cached pin-sense value */ |
22 | unsigned int jack_detect:1; /* capable of jack-detection? */ | 22 | unsigned int jack_detect:1; /* capable of jack-detection? */ |
23 | unsigned int jack_dirty:1; /* needs to update? */ | 23 | unsigned int jack_dirty:1; /* needs to update? */ |
24 | unsigned int need_notify:1; /* to be notified? */ | ||
25 | struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ | 24 | struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ |
26 | }; | 25 | }; |
27 | 26 | ||