aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_jack.c
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2012-11-19 13:48:07 -0500
committerTakashi Iwai <tiwai@suse.de>2012-11-19 13:49:58 -0500
commit0619ba8c17b121ef0273be181198659b17d84247 (patch)
tree81cb3273e7376734b517d4695efa3d02455458ad /sound/pci/hda/hda_jack.c
parent379170a42c84cee5f95fac536a4b5b76843baf90 (diff)
ALSA: hda - Allow jack state to depend on another jack
Introduce the concept of a "gated" jack. The gated jack's pin sense is only valid when the "gating" jack is plugged. This requires checking the gating jack when the gated jack changes and re-checking the gated jack when the gating jack is plugged/unplugged. This allows handling of devices where the mic jack detect floats when the headphone jack is unplugged. [Rewritten for fixing the possible snd_array reallocation, covering the missing callback calls and jack sync operations, as well as some code cleanups -- tiwai] Signed-off-by: Dylan Reid <dgreid@chromium.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/hda_jack.c')
-rw-r--r--sound/pci/hda/hda_jack.c72
1 files changed, 63 insertions, 9 deletions
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 5bdbadaa20fe..4e1948001338 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -122,6 +122,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec)
122 snd_array_free(&codec->jacktbl); 122 snd_array_free(&codec->jacktbl);
123} 123}
124 124
125#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
126
125/* update the cached value and notification flag if needed */ 127/* update the cached value and notification flag if needed */
126static void jack_detect_update(struct hda_codec *codec, 128static void jack_detect_update(struct hda_codec *codec,
127 struct hda_jack_tbl *jack) 129 struct hda_jack_tbl *jack)
@@ -134,7 +136,21 @@ static void jack_detect_update(struct hda_codec *codec,
134 else 136 else
135 jack->pin_sense = read_pin_sense(codec, jack->nid); 137 jack->pin_sense = read_pin_sense(codec, jack->nid);
136 138
139 /* A gating jack indicates the jack is invalid if gating is unplugged */
140 if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack))
141 jack->pin_sense &= ~AC_PINSENSE_PRESENCE;
142
137 jack->jack_dirty = 0; 143 jack->jack_dirty = 0;
144
145 /* If a jack is gated by this one update it. */
146 if (jack->gated_jack) {
147 struct hda_jack_tbl *gated =
148 snd_hda_jack_tbl_get(codec, jack->gated_jack);
149 if (gated) {
150 gated->jack_dirty = 1;
151 jack_detect_update(codec, gated);
152 }
153 }
138} 154}
139 155
140/** 156/**
@@ -173,8 +189,6 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
173} 189}
174EXPORT_SYMBOL_HDA(snd_hda_pin_sense); 190EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
175 191
176#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
177
178/** 192/**
179 * snd_hda_jack_detect - query pin Presence Detect status 193 * snd_hda_jack_detect - query pin Presence Detect status
180 * @codec: the CODEC to sense 194 * @codec: the CODEC to sense
@@ -222,16 +236,46 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
222EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); 236EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
223 237
224/** 238/**
239 * snd_hda_jack_set_gating_jack - Set gating jack.
240 *
241 * Indicates the gated jack is only valid when the gating jack is plugged.
242 */
243int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
244 hda_nid_t gating_nid)
245{
246 struct hda_jack_tbl *gated = snd_hda_jack_tbl_get(codec, gated_nid);
247 struct hda_jack_tbl *gating = snd_hda_jack_tbl_get(codec, gating_nid);
248
249 if (!gated || !gating)
250 return -EINVAL;
251
252 gated->gating_jack = gating_nid;
253 gating->gated_jack = gated_nid;
254
255 return 0;
256}
257EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack);
258
259/**
225 * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 260 * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
226 */ 261 */
227void snd_hda_jack_report_sync(struct hda_codec *codec) 262void snd_hda_jack_report_sync(struct hda_codec *codec)
228{ 263{
229 struct hda_jack_tbl *jack = codec->jacktbl.list; 264 struct hda_jack_tbl *jack;
230 int i, state; 265 int i, state;
231 266
267 /* update all jacks at first */
268 jack = codec->jacktbl.list;
232 for (i = 0; i < codec->jacktbl.used; i++, jack++) 269 for (i = 0; i < codec->jacktbl.used; i++, jack++)
233 if (jack->nid) { 270 if (jack->nid)
234 jack_detect_update(codec, jack); 271 jack_detect_update(codec, jack);
272
273 /* report the updated jacks; it's done after updating all jacks
274 * to make sure that all gating jacks properly have been set
275 */
276 jack = codec->jacktbl.list;
277 for (i = 0; i < codec->jacktbl.used; i++, jack++)
278 if (jack->nid) {
235 if (!jack->kctl) 279 if (!jack->kctl)
236 continue; 280 continue;
237 state = get_jack_plug_state(jack->pin_sense); 281 state = get_jack_plug_state(jack->pin_sense);
@@ -424,6 +468,19 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
424} 468}
425EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); 469EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
426 470
471static void call_jack_callback(struct hda_codec *codec,
472 struct hda_jack_tbl *jack)
473{
474 if (jack->callback)
475 jack->callback(codec, jack);
476 if (jack->gated_jack) {
477 struct hda_jack_tbl *gated =
478 snd_hda_jack_tbl_get(codec, jack->gated_jack);
479 if (gated && gated->callback)
480 gated->callback(codec, gated);
481 }
482}
483
427void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 484void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
428{ 485{
429 struct hda_jack_tbl *event; 486 struct hda_jack_tbl *event;
@@ -434,9 +491,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
434 return; 491 return;
435 event->jack_dirty = 1; 492 event->jack_dirty = 1;
436 493
437 if (event->callback) 494 call_jack_callback(codec, event);
438 event->callback(codec, event);
439
440 snd_hda_jack_report_sync(codec); 495 snd_hda_jack_report_sync(codec);
441} 496}
442EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event); 497EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event);
@@ -455,8 +510,7 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
455 if (old_sense == get_jack_plug_state(jack->pin_sense)) 510 if (old_sense == get_jack_plug_state(jack->pin_sense))
456 continue; 511 continue;
457 changes = 1; 512 changes = 1;
458 if (jack->callback) 513 call_jack_callback(codec, jack);
459 jack->callback(codec, jack);
460 } 514 }
461 if (changes) 515 if (changes)
462 snd_hda_jack_report_sync(codec); 516 snd_hda_jack_report_sync(codec);