aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-10-27 18:03:22 -0400
committerTakashi Iwai <tiwai@suse.de>2011-11-16 05:12:17 -0500
commit01a61e12b4602c82bde9797d0e153f3e53c95b04 (patch)
tree04f817cb8cec2bae3edcc9a873aea1b674b146ad
parent1835a0f9a2121ce3198dab67507d4d3e960cc09e (diff)
ALSA: hda - Create jack-detection kcontrols
Create kcontrols for pin jack-detections, which work similarly like jack-input layer. Each control will notify when the jack is plugged or unplugged, and also user can read the value at any time via the normal control API. The control elements are created with iface=CARD, so that they won't appear in the mixer apps. So far, only the pins that enabled the jack-detection are registered. For covering all pins, the transition of the common unsol-tag handling would be needed. Stay tuned. Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/hda_jack.c168
-rw-r--r--sound/pci/hda/hda_jack.h12
-rw-r--r--sound/pci/hda/patch_cirrus.c27
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c6
-rw-r--r--sound/pci/hda/patch_realtek.c7
-rw-r--r--sound/pci/hda/patch_sigmatel.c7
-rw-r--r--sound/pci/hda/patch_via.c7
8 files changed, 232 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 64b78a2e20e0..cee6a00bd85a 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -12,6 +12,7 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <sound/core.h> 14#include <sound/core.h>
15#include <sound/control.h>
15#include "hda_codec.h" 16#include "hda_codec.h"
16#include "hda_local.h" 17#include "hda_local.h"
17#include "hda_jack.h" 18#include "hda_jack.h"
@@ -76,9 +77,13 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
76static void jack_detect_update(struct hda_codec *codec, 77static void jack_detect_update(struct hda_codec *codec,
77 struct hda_jack_tbl *jack) 78 struct hda_jack_tbl *jack)
78{ 79{
79 if (jack->jack_dirty) { 80 if (jack->jack_dirty || !jack->jack_cachable) {
80 jack->pin_sense = read_pin_sense(codec, jack->nid); 81 unsigned int val = read_pin_sense(codec, jack->nid);
81 jack->jack_dirty = 0; 82 jack->jack_dirty = 0;
83 if (val != jack->pin_sense) {
84 jack->need_notify = 1;
85 jack->pin_sense = val;
86 }
82 } 87 }
83} 88}
84 89
@@ -141,8 +146,167 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
141 struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid); 146 struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
142 if (!jack) 147 if (!jack)
143 return -ENOMEM; 148 return -ENOMEM;
149 if (jack->jack_cachable)
150 return 0; /* already registered */
151 jack->jack_cachable = 1;
144 return snd_hda_codec_write_cache(codec, nid, 0, 152 return snd_hda_codec_write_cache(codec, nid, 0,
145 AC_VERB_SET_UNSOLICITED_ENABLE, 153 AC_VERB_SET_UNSOLICITED_ENABLE,
146 AC_USRSP_EN | tag); 154 AC_USRSP_EN | tag);
147} 155}
148EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); 156EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
157
158/* queue the notification when needed */
159static void jack_detect_report(struct hda_codec *codec,
160 struct hda_jack_tbl *jack)
161{
162 jack_detect_update(codec, jack);
163 if (jack->need_notify) {
164 snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE,
165 &jack->kctl->id);
166 jack->need_notify = 0;
167 }
168}
169
170/**
171 * snd_hda_jack_report - notify kctl when the jack state was changed
172 */
173void snd_hda_jack_report(struct hda_codec *codec, hda_nid_t nid)
174{
175 struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
176
177 if (jack)
178 jack_detect_report(codec, jack);
179}
180EXPORT_SYMBOL_HDA(snd_hda_jack_report);
181
182/**
183 * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
184 */
185void snd_hda_jack_report_sync(struct hda_codec *codec)
186{
187 struct hda_jack_tbl *jack = codec->jacktbl.list;
188 int i;
189
190 for (i = 0; i < codec->jacktbl.used; i++, jack++)
191 if (jack->nid) {
192 jack_detect_update(codec, jack);
193 jack_detect_report(codec, jack);
194 }
195}
196EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
197
198/*
199 * jack-detection kcontrols
200 */
201
202#define jack_detect_kctl_info snd_ctl_boolean_mono_info
203
204static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,
205 struct snd_ctl_elem_value *ucontrol)
206{
207 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
208 hda_nid_t nid = kcontrol->private_value;
209
210 ucontrol->value.integer.value[0] = snd_hda_jack_detect(codec, nid);
211 return 0;
212}
213
214static struct snd_kcontrol_new jack_detect_kctl = {
215 /* name is filled later */
216 .iface = SNDRV_CTL_ELEM_IFACE_CARD,
217 .access = SNDRV_CTL_ELEM_ACCESS_READ,
218 .info = jack_detect_kctl_info,
219 .get = jack_detect_kctl_get,
220};
221
222/**
223 * snd_hda_jack_add_kctl - Add a kctl for the given pin
224 *
225 * This assigns a jack-detection kctl to the given pin. The kcontrol
226 * will have the given name and index.
227 */
228int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
229 const char *name, int idx)
230{
231 struct hda_jack_tbl *jack;
232 struct snd_kcontrol *kctl;
233
234 jack = snd_hda_jack_tbl_get(codec, nid);
235 if (!jack)
236 return 0;
237 if (jack->kctl)
238 return 0; /* already created */
239 kctl = snd_ctl_new1(&jack_detect_kctl, codec);
240 if (!kctl)
241 return -ENOMEM;
242 snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name);
243 kctl->id.index = idx;
244 kctl->private_value = nid;
245 if (snd_hda_ctl_add(codec, nid, kctl) < 0)
246 return -ENOMEM;
247 jack->kctl = kctl;
248 return 0;
249}
250
251static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int idx,
252 const struct auto_pin_cfg *cfg)
253{
254 if (!nid)
255 return 0;
256 if (!is_jack_detectable(codec, nid))
257 return 0;
258 return snd_hda_jack_add_kctl(codec, nid,
259 snd_hda_get_pin_label(codec, nid, cfg),
260 idx);
261}
262
263/**
264 * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
265 *
266 * As of now, it assigns only to the pins that enabled the detection.
267 * Usually this is called at the end of build_controls callback.
268 */
269int snd_hda_jack_add_kctls(struct hda_codec *codec,
270 const struct auto_pin_cfg *cfg)
271{
272 const hda_nid_t *p;
273 int i, err;
274
275 for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
276 err = add_jack_kctl(codec, *p, i, cfg);
277 if (err < 0)
278 return err;
279 }
280 for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
281 if (*p == *cfg->line_out_pins) /* might be duplicated */
282 break;
283 err = add_jack_kctl(codec, *p, i, cfg);
284 if (err < 0)
285 return err;
286 }
287 for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
288 if (*p == *cfg->line_out_pins) /* might be duplicated */
289 break;
290 err = add_jack_kctl(codec, *p, i, cfg);
291 if (err < 0)
292 return err;
293 }
294 for (i = 0; i < cfg->num_inputs; i++) {
295 err = add_jack_kctl(codec, cfg->inputs[i].pin, 0, cfg);
296 if (err < 0)
297 return err;
298 }
299 for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
300 err = add_jack_kctl(codec, *p, i, cfg);
301 if (err < 0)
302 return err;
303 }
304 err = add_jack_kctl(codec, cfg->dig_in_pin, 0, cfg);
305 if (err < 0)
306 return err;
307 err = add_jack_kctl(codec, cfg->mono_out_pin, 0, cfg);
308 if (err < 0)
309 return err;
310 return 0;
311}
312EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 5c1bcb8cf565..b5983eaea51e 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -15,7 +15,10 @@
15struct hda_jack_tbl { 15struct hda_jack_tbl {
16 hda_nid_t nid; 16 hda_nid_t nid;
17 unsigned int pin_sense; /* cached pin-sense value */ 17 unsigned int pin_sense; /* cached pin-sense value */
18 unsigned int jack_cachable:1; /* can be updated via unsol events */
18 unsigned int jack_dirty:1; /* needs to update? */ 19 unsigned int jack_dirty:1; /* needs to update? */
20 unsigned int need_notify:1; /* to be notified? */
21 struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */
19}; 22};
20 23
21struct hda_jack_tbl * 24struct hda_jack_tbl *
@@ -60,4 +63,13 @@ static inline bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
60 return true; 63 return true;
61} 64}
62 65
66int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
67 const char *name, int idx);
68int snd_hda_jack_add_kctls(struct hda_codec *codec,
69 const struct auto_pin_cfg *cfg);
70
71void snd_hda_jack_report(struct hda_codec *codec, hda_nid_t nid);
72void snd_hda_jack_report_sync(struct hda_codec *codec);
73
74
63#endif /* __SOUND_HDA_JACK_H */ 75#endif /* __SOUND_HDA_JACK_H */
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index 6f158777f71a..135fd49cd49d 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1192,11 +1192,14 @@ static int cs_init(struct hda_codec *codec)
1192 init_output(codec); 1192 init_output(codec);
1193 init_input(codec); 1193 init_input(codec);
1194 init_digital(codec); 1194 init_digital(codec);
1195 snd_hda_jack_report_sync(codec);
1196
1195 return 0; 1197 return 0;
1196} 1198}
1197 1199
1198static int cs_build_controls(struct hda_codec *codec) 1200static int cs_build_controls(struct hda_codec *codec)
1199{ 1201{
1202 struct cs_spec *spec = codec->spec;
1200 int err; 1203 int err;
1201 1204
1202 err = build_output(codec); 1205 err = build_output(codec);
@@ -1211,7 +1214,15 @@ static int cs_build_controls(struct hda_codec *codec)
1211 err = build_digital_input(codec); 1214 err = build_digital_input(codec);
1212 if (err < 0) 1215 if (err < 0)
1213 return err; 1216 return err;
1214 return cs_init(codec); 1217 err = cs_init(codec);
1218 if (err < 0)
1219 return err;
1220
1221 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
1222 if (err < 0)
1223 return err;
1224
1225 return 0;
1215} 1226}
1216 1227
1217static void cs_free(struct hda_codec *codec) 1228static void cs_free(struct hda_codec *codec)
@@ -1234,6 +1245,7 @@ static void cs_unsol_event(struct hda_codec *codec, unsigned int res)
1234 cs_automic(codec); 1245 cs_automic(codec);
1235 break; 1246 break;
1236 } 1247 }
1248 snd_hda_jack_report_sync(codec);
1237} 1249}
1238 1250
1239static const struct hda_codec_ops cs_patch_ops = { 1251static const struct hda_codec_ops cs_patch_ops = {
@@ -1611,6 +1623,7 @@ static int cs421x_init(struct hda_codec *codec)
1611 init_output(codec); 1623 init_output(codec);
1612 init_input(codec); 1624 init_input(codec);
1613 init_cs421x_digital(codec); 1625 init_cs421x_digital(codec);
1626 snd_hda_jack_report_sync(codec);
1614 1627
1615 return 0; 1628 return 0;
1616} 1629}
@@ -1786,6 +1799,7 @@ static int build_cs421x_output(struct hda_codec *codec)
1786 1799
1787static int cs421x_build_controls(struct hda_codec *codec) 1800static int cs421x_build_controls(struct hda_codec *codec)
1788{ 1801{
1802 struct cs_spec *spec = codec->spec;
1789 int err; 1803 int err;
1790 1804
1791 err = build_cs421x_output(codec); 1805 err = build_cs421x_output(codec);
@@ -1797,7 +1811,15 @@ static int cs421x_build_controls(struct hda_codec *codec)
1797 err = build_digital_output(codec); 1811 err = build_digital_output(codec);
1798 if (err < 0) 1812 if (err < 0)
1799 return err; 1813 return err;
1800 return cs421x_init(codec); 1814 err = cs421x_init(codec);
1815 if (err < 0)
1816 return err;
1817
1818 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
1819 if (err < 0)
1820 return err;
1821
1822 return 0;
1801} 1823}
1802 1824
1803static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) 1825static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
@@ -1814,6 +1836,7 @@ static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res)
1814 cs_automic(codec); 1836 cs_automic(codec);
1815 break; 1837 break;
1816 } 1838 }
1839 snd_hda_jack_report_sync(codec);
1817} 1840}
1818 1841
1819static int parse_cs421x_input(struct hda_codec *codec) 1842static int parse_cs421x_input(struct hda_codec *codec)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 220e567ccfff..25fdd1e9561f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3770,6 +3770,7 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
3770 snd_hda_input_jack_report(codec, nid); 3770 snd_hda_input_jack_report(codec, nid);
3771 break; 3771 break;
3772 } 3772 }
3773 snd_hda_jack_report_sync(codec);
3773} 3774}
3774 3775
3775/* check whether the pin config is suitable for auto-mic switching; 3776/* check whether the pin config is suitable for auto-mic switching;
@@ -4095,6 +4096,7 @@ static int cx_auto_init(struct hda_codec *codec)
4095 cx_auto_init_output(codec); 4096 cx_auto_init_output(codec);
4096 cx_auto_init_input(codec); 4097 cx_auto_init_input(codec);
4097 cx_auto_init_digital(codec); 4098 cx_auto_init_digital(codec);
4099 snd_hda_jack_report_sync(codec);
4098 return 0; 4100 return 0;
4099} 4101}
4100 4102
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index ea6d85d48444..f01c5efde8e1 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -769,6 +769,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
769 769
770 snd_hda_jack_set_dirty(codec, pin_nid); 770 snd_hda_jack_set_dirty(codec, pin_nid);
771 hdmi_present_sense(&spec->pins[pin_idx], true); 771 hdmi_present_sense(&spec->pins[pin_idx], true);
772 snd_hda_jack_report_sync(codec);
772} 773}
773 774
774static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) 775static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -1268,6 +1269,10 @@ static int generic_hdmi_build_controls(struct hda_codec *codec)
1268 1269
1269 if (err < 0) 1270 if (err < 0)
1270 return err; 1271 return err;
1272 err = snd_hda_jack_add_kctl(codec, per_pin->pin_nid,
1273 "HDMI", pin_idx);
1274 if (err < 0)
1275 return err;
1271 } 1276 }
1272 1277
1273 return 0; 1278 return 0;
@@ -1290,6 +1295,7 @@ static int generic_hdmi_init(struct hda_codec *codec)
1290 INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); 1295 INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
1291 snd_hda_eld_proc_new(codec, eld, pin_idx); 1296 snd_hda_eld_proc_new(codec, eld, pin_idx);
1292 } 1297 }
1298 snd_hda_jack_report_sync(codec);
1293 return 0; 1299 return 0;
1294} 1300}
1295 1301
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index da9d2276e68b..04beae034fea 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -677,6 +677,7 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
677 alc_mic_automute(codec); 677 alc_mic_automute(codec);
678 break; 678 break;
679 } 679 }
680 snd_hda_jack_report_sync(codec);
680} 681}
681 682
682/* call init functions of standard auto-mute helpers */ 683/* call init functions of standard auto-mute helpers */
@@ -2054,6 +2055,10 @@ static int alc_build_controls(struct hda_codec *codec)
2054 2055
2055 alc_free_kctls(codec); /* no longer needed */ 2056 alc_free_kctls(codec); /* no longer needed */
2056 2057
2058 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
2059 if (err < 0)
2060 return err;
2061
2057 return 0; 2062 return 0;
2058} 2063}
2059 2064
@@ -2081,6 +2086,8 @@ static int alc_init(struct hda_codec *codec)
2081 2086
2082 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); 2087 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
2083 2088
2089 snd_hda_jack_report_sync(codec);
2090
2084 hda_call_check_power_status(codec, 0x01); 2091 hda_call_check_power_status(codec, 0x01);
2085 return 0; 2092 return 0;
2086} 2093}
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 97c6df9db5e9..90954b8269c3 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1212,6 +1212,10 @@ static int stac92xx_build_controls(struct hda_codec *codec)
1212 return err; 1212 return err;
1213 } 1213 }
1214 1214
1215 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
1216 if (err < 0)
1217 return err;
1218
1215 return 0; 1219 return 0;
1216} 1220}
1217 1221
@@ -4473,6 +4477,8 @@ static int stac92xx_init(struct hda_codec *codec)
4473 stac_toggle_power_map(codec, nid, 0); 4477 stac_toggle_power_map(codec, nid, 0);
4474 } 4478 }
4475 4479
4480 snd_hda_jack_report_sync(codec);
4481
4476 /* sync mute LED */ 4482 /* sync mute LED */
4477 if (spec->gpio_led) 4483 if (spec->gpio_led)
4478 hda_call_check_power_status(codec, 0x01); 4484 hda_call_check_power_status(codec, 0x01);
@@ -4868,6 +4874,7 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
4868 return; 4874 return;
4869 snd_hda_jack_set_dirty(codec, event->nid); 4875 snd_hda_jack_set_dirty(codec, event->nid);
4870 handle_unsol_event(codec, event); 4876 handle_unsol_event(codec, event);
4877 snd_hda_jack_report_sync(codec);
4871} 4878}
4872 4879
4873static int hp_blike_system(u32 subsystem_id); 4880static int hp_blike_system(u32 subsystem_id);
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 3467d0c23fe9..852939658ddb 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1500,6 +1500,11 @@ static int via_build_controls(struct hda_codec *codec)
1500 analog_low_current_mode(codec); 1500 analog_low_current_mode(codec);
1501 1501
1502 via_free_kctls(codec); /* no longer needed */ 1502 via_free_kctls(codec); /* no longer needed */
1503
1504 err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
1505 if (err < 0)
1506 return err;
1507
1503 return 0; 1508 return 0;
1504} 1509}
1505 1510
@@ -1722,6 +1727,7 @@ static void via_unsol_event(struct hda_codec *codec,
1722 via_hp_automute(codec); 1727 via_hp_automute(codec);
1723 else if (res == VIA_GPIO_EVENT) 1728 else if (res == VIA_GPIO_EVENT)
1724 via_gpio_control(codec); 1729 via_gpio_control(codec);
1730 snd_hda_jack_report_sync(codec);
1725} 1731}
1726 1732
1727#ifdef CONFIG_PM 1733#ifdef CONFIG_PM
@@ -2771,6 +2777,7 @@ static int via_init(struct hda_codec *codec)
2771 via_auto_init_unsol_event(codec); 2777 via_auto_init_unsol_event(codec);
2772 2778
2773 via_hp_automute(codec); 2779 via_hp_automute(codec);
2780 snd_hda_jack_report_sync(codec);
2774 2781
2775 return 0; 2782 return 0;
2776} 2783}