diff options
author | Takashi Iwai <tiwai@suse.de> | 2006-08-23 12:34:06 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:43:56 -0400 |
commit | 071c73ad5fce436ee00c9422b7ca0c5d629451fb (patch) | |
tree | ac8c6776f2b4acb24e22c8c55c61832144fc140a /sound/pci | |
parent | 11b44bbde52b6c50ed8c9ba579d7ee9ff5b48cd8 (diff) |
[ALSA] hda-codec - Fix mic capture with generic parser
Fixed the mic capture with generic parser of hda-codec driver
- Use VREF80 for mic pins if available
- Handle multiple inputs correctly on audio-input widget node.
Confirmed on a conexant codec chip.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/hda_generic.c | 128 |
1 files changed, 90 insertions, 38 deletions
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 85ad164ada59..dedfc5b1083a 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -461,14 +461,19 @@ static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) | |||
461 | return "Front Line"; | 461 | return "Front Line"; |
462 | return "Line"; | 462 | return "Line"; |
463 | case AC_JACK_CD: | 463 | case AC_JACK_CD: |
464 | #if 0 | ||
464 | if (pinctl) | 465 | if (pinctl) |
465 | *pinctl |= AC_PINCTL_VREF_GRD; | 466 | *pinctl |= AC_PINCTL_VREF_GRD; |
467 | #endif | ||
466 | return "CD"; | 468 | return "CD"; |
467 | case AC_JACK_AUX: | 469 | case AC_JACK_AUX: |
468 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 470 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
469 | return "Front Aux"; | 471 | return "Front Aux"; |
470 | return "Aux"; | 472 | return "Aux"; |
471 | case AC_JACK_MIC_IN: | 473 | case AC_JACK_MIC_IN: |
474 | if (node->pin_caps & | ||
475 | (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT)) | ||
476 | *pinctl |= AC_PINCTL_VREF_80; | ||
472 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) | 477 | if ((location & 0x0f) == AC_JACK_LOC_FRONT) |
473 | return "Front Mic"; | 478 | return "Front Mic"; |
474 | return "Mic"; | 479 | return "Mic"; |
@@ -556,6 +561,29 @@ static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, | |||
556 | return 1; /* found */ | 561 | return 1; /* found */ |
557 | } | 562 | } |
558 | 563 | ||
564 | /* add a capture source element */ | ||
565 | static void add_cap_src(struct hda_gspec *spec, int idx) | ||
566 | { | ||
567 | struct hda_input_mux_item *csrc; | ||
568 | char *buf; | ||
569 | int num, ocap; | ||
570 | |||
571 | num = spec->input_mux.num_items; | ||
572 | csrc = &spec->input_mux.items[num]; | ||
573 | buf = spec->cap_labels[num]; | ||
574 | for (ocap = 0; ocap < num; ocap++) { | ||
575 | if (! strcmp(buf, spec->cap_labels[ocap])) { | ||
576 | /* same label already exists, | ||
577 | * put the index number to be unique | ||
578 | */ | ||
579 | sprintf(buf, "%s %d", spec->cap_labels[ocap], num); | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | csrc->index = idx; | ||
584 | spec->input_mux.num_items++; | ||
585 | } | ||
586 | |||
559 | /* | 587 | /* |
560 | * parse input | 588 | * parse input |
561 | */ | 589 | */ |
@@ -576,28 +604,26 @@ static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) | |||
576 | * if it reaches to a proper input PIN, add the path as the | 604 | * if it reaches to a proper input PIN, add the path as the |
577 | * input path. | 605 | * input path. |
578 | */ | 606 | */ |
607 | /* first, check the direct connections to PIN widgets */ | ||
579 | for (i = 0; i < adc_node->nconns; i++) { | 608 | for (i = 0; i < adc_node->nconns; i++) { |
580 | node = hda_get_node(spec, adc_node->conn_list[i]); | 609 | node = hda_get_node(spec, adc_node->conn_list[i]); |
581 | if (! node) | 610 | if (node && node->type == AC_WID_PIN) { |
582 | continue; | 611 | err = parse_adc_sub_nodes(codec, spec, node); |
583 | err = parse_adc_sub_nodes(codec, spec, node); | 612 | if (err < 0) |
584 | if (err < 0) | 613 | return err; |
585 | return err; | 614 | else if (err > 0) |
586 | else if (err > 0) { | 615 | add_cap_src(spec, i); |
587 | struct hda_input_mux_item *csrc = &spec->input_mux.items[spec->input_mux.num_items]; | 616 | } |
588 | char *buf = spec->cap_labels[spec->input_mux.num_items]; | 617 | } |
589 | int ocap; | 618 | /* ... then check the rests, more complicated connections */ |
590 | for (ocap = 0; ocap < spec->input_mux.num_items; ocap++) { | 619 | for (i = 0; i < adc_node->nconns; i++) { |
591 | if (! strcmp(buf, spec->cap_labels[ocap])) { | 620 | node = hda_get_node(spec, adc_node->conn_list[i]); |
592 | /* same label already exists, | 621 | if (node && node->type != AC_WID_PIN) { |
593 | * put the index number to be unique | 622 | err = parse_adc_sub_nodes(codec, spec, node); |
594 | */ | 623 | if (err < 0) |
595 | sprintf(buf, "%s %d", spec->cap_labels[ocap], | 624 | return err; |
596 | spec->input_mux.num_items); | 625 | else if (err > 0) |
597 | } | 626 | add_cap_src(spec, i); |
598 | } | ||
599 | csrc->index = i; | ||
600 | spec->input_mux.num_items++; | ||
601 | } | 627 | } |
602 | } | 628 | } |
603 | 629 | ||
@@ -647,9 +673,6 @@ static int parse_input(struct hda_codec *codec) | |||
647 | /* | 673 | /* |
648 | * create mixer controls if possible | 674 | * create mixer controls if possible |
649 | */ | 675 | */ |
650 | #define DIR_OUT 0x1 | ||
651 | #define DIR_IN 0x2 | ||
652 | |||
653 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, | 676 | static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, |
654 | unsigned int index, const char *type, const char *dir_sfx) | 677 | unsigned int index, const char *type, const char *dir_sfx) |
655 | { | 678 | { |
@@ -743,28 +766,57 @@ static int build_input_controls(struct hda_codec *codec) | |||
743 | { | 766 | { |
744 | struct hda_gspec *spec = codec->spec; | 767 | struct hda_gspec *spec = codec->spec; |
745 | struct hda_gnode *adc_node = spec->adc_node; | 768 | struct hda_gnode *adc_node = spec->adc_node; |
746 | int err; | 769 | int i, err; |
747 | 770 | static struct snd_kcontrol_new cap_sel = { | |
748 | if (! adc_node) | 771 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
772 | .name = "Capture Source", | ||
773 | .info = capture_source_info, | ||
774 | .get = capture_source_get, | ||
775 | .put = capture_source_put, | ||
776 | }; | ||
777 | |||
778 | if (! adc_node || ! spec->input_mux.num_items) | ||
749 | return 0; /* not found */ | 779 | return 0; /* not found */ |
750 | 780 | ||
781 | spec->cur_cap_src = 0; | ||
782 | select_input_connection(codec, adc_node, | ||
783 | spec->input_mux.items[0].index); | ||
784 | |||
751 | /* create capture volume and switch controls if the ADC has an amp */ | 785 | /* create capture volume and switch controls if the ADC has an amp */ |
752 | err = create_mixer(codec, adc_node, 0, NULL, "Capture"); | 786 | /* do we have only a single item? */ |
787 | if (spec->input_mux.num_items == 1) { | ||
788 | err = create_mixer(codec, adc_node, | ||
789 | spec->input_mux.items[0].index, | ||
790 | NULL, "Capture"); | ||
791 | if (err < 0) | ||
792 | return err; | ||
793 | return 0; | ||
794 | } | ||
753 | 795 | ||
754 | /* create input MUX if multiple sources are available */ | 796 | /* create input MUX if multiple sources are available */ |
755 | if (spec->input_mux.num_items > 1) { | 797 | if ((err = snd_ctl_add(codec->bus->card, |
756 | static struct snd_kcontrol_new cap_sel = { | 798 | snd_ctl_new1(&cap_sel, codec))) < 0) |
757 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 799 | return err; |
758 | .name = "Capture Source", | 800 | |
759 | .info = capture_source_info, | 801 | /* no volume control? */ |
760 | .get = capture_source_get, | 802 | if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || |
761 | .put = capture_source_put, | 803 | ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) |
762 | }; | 804 | return 0; |
763 | if ((err = snd_ctl_add(codec->bus->card, snd_ctl_new1(&cap_sel, codec))) < 0) | 805 | |
806 | for (i = 0; i < spec->input_mux.num_items; i++) { | ||
807 | struct snd_kcontrol_new knew; | ||
808 | char name[32]; | ||
809 | sprintf(name, "%s Capture Volume", | ||
810 | spec->input_mux.items[i].label); | ||
811 | knew = (struct snd_kcontrol_new) | ||
812 | HDA_CODEC_VOLUME(name, adc_node->nid, | ||
813 | spec->input_mux.items[i].index, | ||
814 | HDA_INPUT); | ||
815 | if ((err = snd_ctl_add(codec->bus->card, | ||
816 | snd_ctl_new1(&knew, codec))) < 0) | ||
764 | return err; | 817 | return err; |
765 | spec->cur_cap_src = 0; | ||
766 | select_input_connection(codec, adc_node, spec->input_mux.items[0].index); | ||
767 | } | 818 | } |
819 | |||
768 | return 0; | 820 | return 0; |
769 | } | 821 | } |
770 | 822 | ||