diff options
Diffstat (limited to 'sound/pci/hda/hda_jack.c')
-rw-r--r-- | sound/pci/hda/hda_jack.c | 102 |
1 files changed, 70 insertions, 32 deletions
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 2dd1c113a4c1..aaccc0236bda 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c | |||
@@ -127,10 +127,15 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) | |||
127 | static void jack_detect_update(struct hda_codec *codec, | 127 | static void jack_detect_update(struct hda_codec *codec, |
128 | struct hda_jack_tbl *jack) | 128 | struct hda_jack_tbl *jack) |
129 | { | 129 | { |
130 | if (jack->jack_dirty || !jack->jack_detect) { | 130 | if (!jack->jack_dirty) |
131 | return; | ||
132 | |||
133 | if (jack->phantom_jack) | ||
134 | jack->pin_sense = AC_PINSENSE_PRESENCE; | ||
135 | else | ||
131 | jack->pin_sense = read_pin_sense(codec, jack->nid); | 136 | jack->pin_sense = read_pin_sense(codec, jack->nid); |
132 | jack->jack_dirty = 0; | 137 | |
133 | } | 138 | jack->jack_dirty = 0; |
134 | } | 139 | } |
135 | 140 | ||
136 | /** | 141 | /** |
@@ -264,8 +269,8 @@ static void hda_free_jack_priv(struct snd_jack *jack) | |||
264 | * This assigns a jack-detection kctl to the given pin. The kcontrol | 269 | * This assigns a jack-detection kctl to the given pin. The kcontrol |
265 | * will have the given name and index. | 270 | * will have the given name and index. |
266 | */ | 271 | */ |
267 | int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, | 272 | static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, |
268 | const char *name, int idx) | 273 | const char *name, int idx, bool phantom_jack) |
269 | { | 274 | { |
270 | struct hda_jack_tbl *jack; | 275 | struct hda_jack_tbl *jack; |
271 | struct snd_kcontrol *kctl; | 276 | struct snd_kcontrol *kctl; |
@@ -283,47 +288,81 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, | |||
283 | if (err < 0) | 288 | if (err < 0) |
284 | return err; | 289 | return err; |
285 | jack->kctl = kctl; | 290 | jack->kctl = kctl; |
291 | jack->phantom_jack = !!phantom_jack; | ||
292 | |||
286 | state = snd_hda_jack_detect(codec, nid); | 293 | state = snd_hda_jack_detect(codec, nid); |
287 | snd_kctl_jack_report(codec->bus->card, kctl, state); | 294 | snd_kctl_jack_report(codec->bus->card, kctl, state); |
288 | #ifdef CONFIG_SND_HDA_INPUT_JACK | 295 | #ifdef CONFIG_SND_HDA_INPUT_JACK |
289 | jack->type = get_input_jack_type(codec, nid); | 296 | if (!phantom_jack) { |
290 | err = snd_jack_new(codec->bus->card, name, jack->type, &jack->jack); | 297 | jack->type = get_input_jack_type(codec, nid); |
291 | if (err < 0) | 298 | err = snd_jack_new(codec->bus->card, name, jack->type, |
292 | return err; | 299 | &jack->jack); |
293 | jack->jack->private_data = jack; | 300 | if (err < 0) |
294 | jack->jack->private_free = hda_free_jack_priv; | 301 | return err; |
295 | snd_jack_report(jack->jack, state ? jack->type : 0); | 302 | jack->jack->private_data = jack; |
303 | jack->jack->private_free = hda_free_jack_priv; | ||
304 | snd_jack_report(jack->jack, state ? jack->type : 0); | ||
305 | } | ||
296 | #endif | 306 | #endif |
297 | return 0; | 307 | return 0; |
298 | } | 308 | } |
309 | |||
310 | int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, | ||
311 | const char *name, int idx) | ||
312 | { | ||
313 | return __snd_hda_jack_add_kctl(codec, nid, name, idx, false); | ||
314 | } | ||
299 | EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); | 315 | EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); |
300 | 316 | ||
317 | /* get the unique index number for the given kctl name */ | ||
318 | static int get_unique_index(struct hda_codec *codec, const char *name, int idx) | ||
319 | { | ||
320 | struct hda_jack_tbl *jack; | ||
321 | int i, len = strlen(name); | ||
322 | again: | ||
323 | jack = codec->jacktbl.list; | ||
324 | for (i = 0; i < codec->jacktbl.used; i++, jack++) { | ||
325 | /* jack->kctl.id contains "XXX Jack" name string with index */ | ||
326 | if (jack->kctl && | ||
327 | !strncmp(name, jack->kctl->id.name, len) && | ||
328 | !strcmp(" Jack", jack->kctl->id.name + len) && | ||
329 | jack->kctl->id.index == idx) { | ||
330 | idx++; | ||
331 | goto again; | ||
332 | } | ||
333 | } | ||
334 | return idx; | ||
335 | } | ||
336 | |||
301 | static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, | 337 | static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, |
302 | const struct auto_pin_cfg *cfg, | 338 | const struct auto_pin_cfg *cfg) |
303 | char *lastname, int *lastidx) | ||
304 | { | 339 | { |
305 | unsigned int def_conf, conn; | 340 | unsigned int def_conf, conn; |
306 | char name[44]; | 341 | char name[44]; |
307 | int idx, err; | 342 | int idx, err; |
343 | bool phantom_jack; | ||
308 | 344 | ||
309 | if (!nid) | 345 | if (!nid) |
310 | return 0; | 346 | return 0; |
311 | if (!is_jack_detectable(codec, nid)) | ||
312 | return 0; | ||
313 | def_conf = snd_hda_codec_get_pincfg(codec, nid); | 347 | def_conf = snd_hda_codec_get_pincfg(codec, nid); |
314 | conn = get_defcfg_connect(def_conf); | 348 | conn = get_defcfg_connect(def_conf); |
315 | if (conn != AC_JACK_PORT_COMPLEX) | 349 | if (conn == AC_JACK_PORT_NONE) |
316 | return 0; | 350 | return 0; |
351 | phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || | ||
352 | !is_jack_detectable(codec, nid); | ||
317 | 353 | ||
318 | snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); | 354 | snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); |
319 | if (!strcmp(name, lastname) && idx == *lastidx) | 355 | if (phantom_jack) |
320 | idx++; | 356 | /* Example final name: "Internal Mic Phantom Jack" */ |
321 | strncpy(lastname, name, 44); | 357 | strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); |
322 | *lastidx = idx; | 358 | idx = get_unique_index(codec, name, idx); |
323 | err = snd_hda_jack_add_kctl(codec, nid, name, idx); | 359 | err = __snd_hda_jack_add_kctl(codec, nid, name, idx, phantom_jack); |
324 | if (err < 0) | 360 | if (err < 0) |
325 | return err; | 361 | return err; |
326 | return snd_hda_jack_detect_enable(codec, nid, 0); | 362 | |
363 | if (!phantom_jack) | ||
364 | return snd_hda_jack_detect_enable(codec, nid, 0); | ||
365 | return 0; | ||
327 | } | 366 | } |
328 | 367 | ||
329 | /** | 368 | /** |
@@ -333,42 +372,41 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, | |||
333 | const struct auto_pin_cfg *cfg) | 372 | const struct auto_pin_cfg *cfg) |
334 | { | 373 | { |
335 | const hda_nid_t *p; | 374 | const hda_nid_t *p; |
336 | int i, err, lastidx = 0; | 375 | int i, err; |
337 | char lastname[44] = ""; | ||
338 | 376 | ||
339 | for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { | 377 | for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { |
340 | err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); | 378 | err = add_jack_kctl(codec, *p, cfg); |
341 | if (err < 0) | 379 | if (err < 0) |
342 | return err; | 380 | return err; |
343 | } | 381 | } |
344 | for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { | 382 | for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { |
345 | if (*p == *cfg->line_out_pins) /* might be duplicated */ | 383 | if (*p == *cfg->line_out_pins) /* might be duplicated */ |
346 | break; | 384 | break; |
347 | err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); | 385 | err = add_jack_kctl(codec, *p, cfg); |
348 | if (err < 0) | 386 | if (err < 0) |
349 | return err; | 387 | return err; |
350 | } | 388 | } |
351 | for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { | 389 | for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { |
352 | if (*p == *cfg->line_out_pins) /* might be duplicated */ | 390 | if (*p == *cfg->line_out_pins) /* might be duplicated */ |
353 | break; | 391 | break; |
354 | err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); | 392 | err = add_jack_kctl(codec, *p, cfg); |
355 | if (err < 0) | 393 | if (err < 0) |
356 | return err; | 394 | return err; |
357 | } | 395 | } |
358 | for (i = 0; i < cfg->num_inputs; i++) { | 396 | for (i = 0; i < cfg->num_inputs; i++) { |
359 | err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, lastname, &lastidx); | 397 | err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg); |
360 | if (err < 0) | 398 | if (err < 0) |
361 | return err; | 399 | return err; |
362 | } | 400 | } |
363 | for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { | 401 | for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { |
364 | err = add_jack_kctl(codec, *p, cfg, lastname, &lastidx); | 402 | err = add_jack_kctl(codec, *p, cfg); |
365 | if (err < 0) | 403 | if (err < 0) |
366 | return err; | 404 | return err; |
367 | } | 405 | } |
368 | err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, lastname, &lastidx); | 406 | err = add_jack_kctl(codec, cfg->dig_in_pin, cfg); |
369 | if (err < 0) | 407 | if (err < 0) |
370 | return err; | 408 | return err; |
371 | err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, lastname, &lastidx); | 409 | err = add_jack_kctl(codec, cfg->mono_out_pin, cfg); |
372 | if (err < 0) | 410 | if (err < 0) |
373 | return err; | 411 | return err; |
374 | return 0; | 412 | return 0; |