11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Universal Interface for Intel High Definition Audio Codec 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Generic widget tree parser 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This driver is free software; you can redistribute it and/or modify 91da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 101da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 111da177e4SLinus Torvalds * (at your option) any later version. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * This driver is distributed in the hope that it will be useful, 141da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4SLinus Torvalds * GNU General Public License for more details. 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 191da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 201da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 211da177e4SLinus Torvalds */ 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <sound/core.h> 261da177e4SLinus Torvalds #include "hda_codec.h" 271da177e4SLinus Torvalds #include "hda_local.h" 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* widget node for parsing */ 301da177e4SLinus Torvalds struct hda_gnode { 311da177e4SLinus Torvalds hda_nid_t nid; /* NID of this widget */ 321da177e4SLinus Torvalds unsigned short nconns; /* number of input connections */ 33d2569505STakashi Iwai hda_nid_t *conn_list; 34d2569505STakashi Iwai hda_nid_t slist[2]; /* temporay list */ 351da177e4SLinus Torvalds unsigned int wid_caps; /* widget capabilities */ 361da177e4SLinus Torvalds unsigned char type; /* widget type */ 371da177e4SLinus Torvalds unsigned char pin_ctl; /* pin controls */ 381da177e4SLinus Torvalds unsigned char checked; /* the flag indicates that the node is already parsed */ 391da177e4SLinus Torvalds unsigned int pin_caps; /* pin widget capabilities */ 401da177e4SLinus Torvalds unsigned int def_cfg; /* default configuration */ 411da177e4SLinus Torvalds unsigned int amp_out_caps; /* AMP out capabilities */ 421da177e4SLinus Torvalds unsigned int amp_in_caps; /* AMP in capabilities */ 431da177e4SLinus Torvalds struct list_head list; 441da177e4SLinus Torvalds }; 451da177e4SLinus Torvalds 46c3132925STakashi Iwai /* patch-specific record */ 47a7da6ce5STakashi Iwai 48a7da6ce5STakashi Iwai #define MAX_PCM_VOLS 2 49a7da6ce5STakashi Iwai struct pcm_vol { 50a7da6ce5STakashi Iwai struct hda_gnode *node; /* Node for PCM volume */ 51a7da6ce5STakashi Iwai unsigned int index; /* connection of PCM volume */ 52a7da6ce5STakashi Iwai }; 53a7da6ce5STakashi Iwai 541da177e4SLinus Torvalds struct hda_gspec { 5597ec558aSTakashi Iwai struct hda_gnode *dac_node[2]; /* DAC node */ 5697ec558aSTakashi Iwai struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ 57a7da6ce5STakashi Iwai struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ 58a7da6ce5STakashi Iwai unsigned int pcm_vol_nodes; /* number of PCM volumes */ 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds struct hda_gnode *adc_node; /* ADC node */ 611da177e4SLinus Torvalds struct hda_gnode *cap_vol_node; /* Node for capture volume */ 621da177e4SLinus Torvalds unsigned int cur_cap_src; /* current capture source */ 631da177e4SLinus Torvalds struct hda_input_mux input_mux; 641da177e4SLinus Torvalds char cap_labels[HDA_MAX_NUM_INPUTS][16]; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds unsigned int def_amp_in_caps; 671da177e4SLinus Torvalds unsigned int def_amp_out_caps; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds struct hda_pcm pcm_rec; /* PCM information */ 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds struct list_head nid_list; /* list of widgets */ 72cb53c626STakashi Iwai 73cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 74cb53c626STakashi Iwai #define MAX_LOOPBACK_AMPS 7 75cb53c626STakashi Iwai struct hda_loopback_check loopback; 76cb53c626STakashi Iwai int num_loopbacks; 77cb53c626STakashi Iwai struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; 78cb53c626STakashi Iwai #endif 791da177e4SLinus Torvalds }; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds /* 821da177e4SLinus Torvalds * retrieve the default device type from the default config value 831da177e4SLinus Torvalds */ 8497ec558aSTakashi Iwai #define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \ 8597ec558aSTakashi Iwai AC_DEFCFG_DEVICE_SHIFT) 8697ec558aSTakashi Iwai #define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \ 8797ec558aSTakashi Iwai AC_DEFCFG_LOCATION_SHIFT) 8897ec558aSTakashi Iwai #define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \ 8997ec558aSTakashi Iwai AC_DEFCFG_PORT_CONN_SHIFT) 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds /* 921da177e4SLinus Torvalds * destructor 931da177e4SLinus Torvalds */ 941da177e4SLinus Torvalds static void snd_hda_generic_free(struct hda_codec *codec) 951da177e4SLinus Torvalds { 961da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 9733206e86SMatthias Kaehlcke struct hda_gnode *node, *n; 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds if (! spec) 1001da177e4SLinus Torvalds return; 1011da177e4SLinus Torvalds /* free all widgets */ 10233206e86SMatthias Kaehlcke list_for_each_entry_safe(node, n, &spec->nid_list, list) { 103d2569505STakashi Iwai if (node->conn_list != node->slist) 104d2569505STakashi Iwai kfree(node->conn_list); 1051da177e4SLinus Torvalds kfree(node); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds kfree(spec); 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* 1121da177e4SLinus Torvalds * add a new widget node and read its attributes 1131da177e4SLinus Torvalds */ 1141da177e4SLinus Torvalds static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) 1151da177e4SLinus Torvalds { 1161da177e4SLinus Torvalds struct hda_gnode *node; 1171da177e4SLinus Torvalds int nconns; 118d2569505STakashi Iwai hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; 1191da177e4SLinus Torvalds 120e560d8d8STakashi Iwai node = kzalloc(sizeof(*node), GFP_KERNEL); 1211da177e4SLinus Torvalds if (node == NULL) 1221da177e4SLinus Torvalds return -ENOMEM; 1231da177e4SLinus Torvalds node->nid = nid; 124d2569505STakashi Iwai nconns = snd_hda_get_connections(codec, nid, conn_list, 125d2569505STakashi Iwai HDA_MAX_CONNECTIONS); 1261da177e4SLinus Torvalds if (nconns < 0) { 1271da177e4SLinus Torvalds kfree(node); 1281da177e4SLinus Torvalds return nconns; 1291da177e4SLinus Torvalds } 130d2569505STakashi Iwai if (nconns <= ARRAY_SIZE(node->slist)) 131d2569505STakashi Iwai node->conn_list = node->slist; 132d2569505STakashi Iwai else { 133d2569505STakashi Iwai node->conn_list = kmalloc(sizeof(hda_nid_t) * nconns, 134d2569505STakashi Iwai GFP_KERNEL); 135d2569505STakashi Iwai if (! node->conn_list) { 136d2569505STakashi Iwai snd_printk(KERN_ERR "hda-generic: cannot malloc\n"); 137d2569505STakashi Iwai kfree(node); 138d2569505STakashi Iwai return -ENOMEM; 139d2569505STakashi Iwai } 140d2569505STakashi Iwai } 1410bbed758STakashi Iwai memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t)); 1421da177e4SLinus Torvalds node->nconns = nconns; 143d2569505STakashi Iwai node->wid_caps = get_wcaps(codec, nid); 1441da177e4SLinus Torvalds node->type = (node->wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds if (node->type == AC_WID_PIN) { 1471da177e4SLinus Torvalds node->pin_caps = snd_hda_param_read(codec, node->nid, AC_PAR_PIN_CAP); 1481da177e4SLinus Torvalds node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); 1491da177e4SLinus Torvalds node->def_cfg = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_OUT_AMP) { 1531da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_AMP_OVRD) 1541da177e4SLinus Torvalds node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); 1551da177e4SLinus Torvalds if (! node->amp_out_caps) 1561da177e4SLinus Torvalds node->amp_out_caps = spec->def_amp_out_caps; 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_IN_AMP) { 1591da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_AMP_OVRD) 1601da177e4SLinus Torvalds node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); 1611da177e4SLinus Torvalds if (! node->amp_in_caps) 1621da177e4SLinus Torvalds node->amp_in_caps = spec->def_amp_in_caps; 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds list_add_tail(&node->list, &spec->nid_list); 1651da177e4SLinus Torvalds return 0; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /* 1691da177e4SLinus Torvalds * build the AFG subtree 1701da177e4SLinus Torvalds */ 1711da177e4SLinus Torvalds static int build_afg_tree(struct hda_codec *codec) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 1741da177e4SLinus Torvalds int i, nodes, err; 1751da177e4SLinus Torvalds hda_nid_t nid; 1761da177e4SLinus Torvalds 177da3cec35STakashi Iwai if (snd_BUG_ON(!spec)) 178da3cec35STakashi Iwai return -EINVAL; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); 1811da177e4SLinus Torvalds spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); 1841da177e4SLinus Torvalds if (! nid || nodes < 0) { 1851da177e4SLinus Torvalds printk(KERN_ERR "Invalid AFG subtree\n"); 1861da177e4SLinus Torvalds return -EINVAL; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds /* parse all nodes belonging to the AFG */ 1901da177e4SLinus Torvalds for (i = 0; i < nodes; i++, nid++) { 1911da177e4SLinus Torvalds if ((err = add_new_node(codec, spec, nid)) < 0) 1921da177e4SLinus Torvalds return err; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds return 0; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds /* 2001da177e4SLinus Torvalds * look for the node record for the given NID 2011da177e4SLinus Torvalds */ 2021da177e4SLinus Torvalds /* FIXME: should avoid the braindead linear search */ 2031da177e4SLinus Torvalds static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) 2041da177e4SLinus Torvalds { 2051da177e4SLinus Torvalds struct hda_gnode *node; 2061da177e4SLinus Torvalds 20733206e86SMatthias Kaehlcke list_for_each_entry(node, &spec->nid_list, list) { 2081da177e4SLinus Torvalds if (node->nid == nid) 2091da177e4SLinus Torvalds return node; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds return NULL; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds /* 2151da177e4SLinus Torvalds * unmute (and set max vol) the output amplifier 2161da177e4SLinus Torvalds */ 2171da177e4SLinus Torvalds static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) 2181da177e4SLinus Torvalds { 2191da177e4SLinus Torvalds unsigned int val, ofs; 2201da177e4SLinus Torvalds snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); 2211da177e4SLinus Torvalds val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 2221da177e4SLinus Torvalds ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 2231da177e4SLinus Torvalds if (val >= ofs) 2241da177e4SLinus Torvalds val -= ofs; 22547fd830aSTakashi Iwai snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); 22682beb8fdSTakashi Iwai return 0; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* 2301da177e4SLinus Torvalds * unmute (and set max vol) the input amplifier 2311da177e4SLinus Torvalds */ 2321da177e4SLinus Torvalds static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds unsigned int val, ofs; 2351da177e4SLinus Torvalds snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); 2361da177e4SLinus Torvalds val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; 2371da177e4SLinus Torvalds ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; 2381da177e4SLinus Torvalds if (val >= ofs) 2391da177e4SLinus Torvalds val -= ofs; 24047fd830aSTakashi Iwai snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); 24182beb8fdSTakashi Iwai return 0; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* 2451da177e4SLinus Torvalds * select the input connection of the given node. 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, 2481da177e4SLinus Torvalds unsigned int index) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); 25182beb8fdSTakashi Iwai return snd_hda_codec_write_cache(codec, node->nid, 0, 25282beb8fdSTakashi Iwai AC_VERB_SET_CONNECT_SEL, index); 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds /* 2561da177e4SLinus Torvalds * clear checked flag of each node in the node list 2571da177e4SLinus Torvalds */ 2581da177e4SLinus Torvalds static void clear_check_flags(struct hda_gspec *spec) 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds struct hda_gnode *node; 2611da177e4SLinus Torvalds 26233206e86SMatthias Kaehlcke list_for_each_entry(node, &spec->nid_list, list) { 2631da177e4SLinus Torvalds node->checked = 0; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * parse the output path recursively until reach to an audio output widget 2691da177e4SLinus Torvalds * 2701da177e4SLinus Torvalds * returns 0 if not found, 1 if found, or a negative error code. 2711da177e4SLinus Torvalds */ 2721da177e4SLinus Torvalds static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, 27397ec558aSTakashi Iwai struct hda_gnode *node, int dac_idx) 2741da177e4SLinus Torvalds { 2751da177e4SLinus Torvalds int i, err; 2761da177e4SLinus Torvalds struct hda_gnode *child; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds if (node->checked) 2791da177e4SLinus Torvalds return 0; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds node->checked = 1; 2821da177e4SLinus Torvalds if (node->type == AC_WID_AUD_OUT) { 2831da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_DIGITAL) { 2841da177e4SLinus Torvalds snd_printdd("Skip Digital OUT node %x\n", node->nid); 2851da177e4SLinus Torvalds return 0; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds snd_printdd("AUD_OUT found %x\n", node->nid); 28897ec558aSTakashi Iwai if (spec->dac_node[dac_idx]) { 2891da177e4SLinus Torvalds /* already DAC node is assigned, just unmute & connect */ 29097ec558aSTakashi Iwai return node == spec->dac_node[dac_idx]; 2911da177e4SLinus Torvalds } 29297ec558aSTakashi Iwai spec->dac_node[dac_idx] = node; 293a7da6ce5STakashi Iwai if ((node->wid_caps & AC_WCAP_OUT_AMP) && 294a7da6ce5STakashi Iwai spec->pcm_vol_nodes < MAX_PCM_VOLS) { 295a7da6ce5STakashi Iwai spec->pcm_vol[spec->pcm_vol_nodes].node = node; 296a7da6ce5STakashi Iwai spec->pcm_vol[spec->pcm_vol_nodes].index = 0; 297a7da6ce5STakashi Iwai spec->pcm_vol_nodes++; 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds return 1; /* found */ 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds for (i = 0; i < node->nconns; i++) { 3031da177e4SLinus Torvalds child = hda_get_node(spec, node->conn_list[i]); 3041da177e4SLinus Torvalds if (! child) 3051da177e4SLinus Torvalds continue; 30697ec558aSTakashi Iwai err = parse_output_path(codec, spec, child, dac_idx); 3071da177e4SLinus Torvalds if (err < 0) 3081da177e4SLinus Torvalds return err; 3091da177e4SLinus Torvalds else if (err > 0) { 3101da177e4SLinus Torvalds /* found one, 3111da177e4SLinus Torvalds * select the path, unmute both input and output 3121da177e4SLinus Torvalds */ 3131da177e4SLinus Torvalds if (node->nconns > 1) 3141da177e4SLinus Torvalds select_input_connection(codec, node, i); 3151da177e4SLinus Torvalds unmute_input(codec, node, i); 3161da177e4SLinus Torvalds unmute_output(codec, node); 317a7da6ce5STakashi Iwai if (spec->dac_node[dac_idx] && 318a7da6ce5STakashi Iwai spec->pcm_vol_nodes < MAX_PCM_VOLS && 319a7da6ce5STakashi Iwai !(spec->dac_node[dac_idx]->wid_caps & 320a7da6ce5STakashi Iwai AC_WCAP_OUT_AMP)) { 321a7da6ce5STakashi Iwai if ((node->wid_caps & AC_WCAP_IN_AMP) || 322a7da6ce5STakashi Iwai (node->wid_caps & AC_WCAP_OUT_AMP)) { 323a7da6ce5STakashi Iwai int n = spec->pcm_vol_nodes; 324a7da6ce5STakashi Iwai spec->pcm_vol[n].node = node; 325a7da6ce5STakashi Iwai spec->pcm_vol[n].index = i; 326a7da6ce5STakashi Iwai spec->pcm_vol_nodes++; 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds return 1; 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds return 0; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds /* 3361da177e4SLinus Torvalds * Look for the output PIN widget with the given jack type 3371da177e4SLinus Torvalds * and parse the output path to that PIN. 3381da177e4SLinus Torvalds * 3391da177e4SLinus Torvalds * Returns the PIN node when the path to DAC is established. 3401da177e4SLinus Torvalds */ 3411da177e4SLinus Torvalds static struct hda_gnode *parse_output_jack(struct hda_codec *codec, 3421da177e4SLinus Torvalds struct hda_gspec *spec, 3431da177e4SLinus Torvalds int jack_type) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds struct hda_gnode *node; 3461da177e4SLinus Torvalds int err; 3471da177e4SLinus Torvalds 34833206e86SMatthias Kaehlcke list_for_each_entry(node, &spec->nid_list, list) { 3491da177e4SLinus Torvalds if (node->type != AC_WID_PIN) 3501da177e4SLinus Torvalds continue; 3511da177e4SLinus Torvalds /* output capable? */ 3521da177e4SLinus Torvalds if (! (node->pin_caps & AC_PINCAP_OUT)) 3531da177e4SLinus Torvalds continue; 35497ec558aSTakashi Iwai if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) 35597ec558aSTakashi Iwai continue; /* unconnected */ 3561da177e4SLinus Torvalds if (jack_type >= 0) { 357e9edcee0STakashi Iwai if (jack_type != defcfg_type(node)) 3581da177e4SLinus Torvalds continue; 3591da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_DIGITAL) 3601da177e4SLinus Torvalds continue; /* skip SPDIF */ 3611da177e4SLinus Torvalds } else { 3621da177e4SLinus Torvalds /* output as default? */ 3631da177e4SLinus Torvalds if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) 3641da177e4SLinus Torvalds continue; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds clear_check_flags(spec); 36797ec558aSTakashi Iwai err = parse_output_path(codec, spec, node, 0); 3681da177e4SLinus Torvalds if (err < 0) 3691da177e4SLinus Torvalds return NULL; 37097ec558aSTakashi Iwai if (! err && spec->out_pin_node[0]) { 37197ec558aSTakashi Iwai err = parse_output_path(codec, spec, node, 1); 37297ec558aSTakashi Iwai if (err < 0) 37397ec558aSTakashi Iwai return NULL; 37497ec558aSTakashi Iwai } 37597ec558aSTakashi Iwai if (err > 0) { 3761da177e4SLinus Torvalds /* unmute the PIN output */ 3771da177e4SLinus Torvalds unmute_output(codec, node); 3781da177e4SLinus Torvalds /* set PIN-Out enable */ 37982beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, node->nid, 0, 3801da177e4SLinus Torvalds AC_VERB_SET_PIN_WIDGET_CONTROL, 381a7da6ce5STakashi Iwai AC_PINCTL_OUT_EN | 382a7da6ce5STakashi Iwai ((node->pin_caps & AC_PINCAP_HP_DRV) ? 383a7da6ce5STakashi Iwai AC_PINCTL_HP_EN : 0)); 3841da177e4SLinus Torvalds return node; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds return NULL; 3881da177e4SLinus Torvalds } 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* 3921da177e4SLinus Torvalds * parse outputs 3931da177e4SLinus Torvalds */ 3941da177e4SLinus Torvalds static int parse_output(struct hda_codec *codec) 3951da177e4SLinus Torvalds { 3961da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 3971da177e4SLinus Torvalds struct hda_gnode *node; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /* 4001da177e4SLinus Torvalds * Look for the output PIN widget 4011da177e4SLinus Torvalds */ 4021da177e4SLinus Torvalds /* first, look for the line-out pin */ 4031da177e4SLinus Torvalds node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); 4041da177e4SLinus Torvalds if (node) /* found, remember the PIN node */ 40597ec558aSTakashi Iwai spec->out_pin_node[0] = node; 40697ec558aSTakashi Iwai else { 40797ec558aSTakashi Iwai /* if no line-out is found, try speaker out */ 40897ec558aSTakashi Iwai node = parse_output_jack(codec, spec, AC_JACK_SPEAKER); 40997ec558aSTakashi Iwai if (node) 41097ec558aSTakashi Iwai spec->out_pin_node[0] = node; 41197ec558aSTakashi Iwai } 4121da177e4SLinus Torvalds /* look for the HP-out pin */ 4131da177e4SLinus Torvalds node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); 4141da177e4SLinus Torvalds if (node) { 41597ec558aSTakashi Iwai if (! spec->out_pin_node[0]) 41697ec558aSTakashi Iwai spec->out_pin_node[0] = node; 41797ec558aSTakashi Iwai else 41897ec558aSTakashi Iwai spec->out_pin_node[1] = node; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 42197ec558aSTakashi Iwai if (! spec->out_pin_node[0]) { 4221da177e4SLinus Torvalds /* no line-out or HP pins found, 4231da177e4SLinus Torvalds * then choose for the first output pin 4241da177e4SLinus Torvalds */ 42597ec558aSTakashi Iwai spec->out_pin_node[0] = parse_output_jack(codec, spec, -1); 42697ec558aSTakashi Iwai if (! spec->out_pin_node[0]) 4271da177e4SLinus Torvalds snd_printd("hda_generic: no proper output path found\n"); 4281da177e4SLinus Torvalds } 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds return 0; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* 4341da177e4SLinus Torvalds * input MUX 4351da177e4SLinus Torvalds */ 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds /* control callbacks */ 438c8b6bf9bSTakashi Iwai static int capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 4391da177e4SLinus Torvalds { 4401da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4411da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 4421da177e4SLinus Torvalds return snd_hda_input_mux_info(&spec->input_mux, uinfo); 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds 445c8b6bf9bSTakashi Iwai static int capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4481da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = spec->cur_cap_src; 4511da177e4SLinus Torvalds return 0; 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds 454c8b6bf9bSTakashi Iwai static int capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4551da177e4SLinus Torvalds { 4561da177e4SLinus Torvalds struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 4571da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 4581da177e4SLinus Torvalds return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, 4591da177e4SLinus Torvalds spec->adc_node->nid, &spec->cur_cap_src); 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds /* 4631da177e4SLinus Torvalds * return the string name of the given input PIN widget 4641da177e4SLinus Torvalds */ 4651da177e4SLinus Torvalds static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) 4661da177e4SLinus Torvalds { 467e9edcee0STakashi Iwai unsigned int location = defcfg_location(node); 468e9edcee0STakashi Iwai switch (defcfg_type(node)) { 4691da177e4SLinus Torvalds case AC_JACK_LINE_IN: 4701da177e4SLinus Torvalds if ((location & 0x0f) == AC_JACK_LOC_FRONT) 4711da177e4SLinus Torvalds return "Front Line"; 4721da177e4SLinus Torvalds return "Line"; 4731da177e4SLinus Torvalds case AC_JACK_CD: 474071c73adSTakashi Iwai #if 0 4751da177e4SLinus Torvalds if (pinctl) 4761a12de1eSMatt *pinctl |= AC_PINCTL_VREF_GRD; 477071c73adSTakashi Iwai #endif 4781da177e4SLinus Torvalds return "CD"; 4791da177e4SLinus Torvalds case AC_JACK_AUX: 4801da177e4SLinus Torvalds if ((location & 0x0f) == AC_JACK_LOC_FRONT) 4811da177e4SLinus Torvalds return "Front Aux"; 4821da177e4SLinus Torvalds return "Aux"; 4831da177e4SLinus Torvalds case AC_JACK_MIC_IN: 4846afeb11dSTakashi Iwai if (pinctl && 4856afeb11dSTakashi Iwai (node->pin_caps & 4866afeb11dSTakashi Iwai (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))) 487071c73adSTakashi Iwai *pinctl |= AC_PINCTL_VREF_80; 4881da177e4SLinus Torvalds if ((location & 0x0f) == AC_JACK_LOC_FRONT) 4891da177e4SLinus Torvalds return "Front Mic"; 4901da177e4SLinus Torvalds return "Mic"; 4911da177e4SLinus Torvalds case AC_JACK_SPDIF_IN: 4921da177e4SLinus Torvalds return "SPDIF"; 4931da177e4SLinus Torvalds case AC_JACK_DIG_OTHER_IN: 4941da177e4SLinus Torvalds return "Digital"; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds return NULL; 4971da177e4SLinus Torvalds } 4981da177e4SLinus Torvalds 4991da177e4SLinus Torvalds /* 5001da177e4SLinus Torvalds * parse the nodes recursively until reach to the input PIN 5011da177e4SLinus Torvalds * 5021da177e4SLinus Torvalds * returns 0 if not found, 1 if found, or a negative error code. 5031da177e4SLinus Torvalds */ 5041da177e4SLinus Torvalds static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, 5051da177e4SLinus Torvalds struct hda_gnode *node) 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds int i, err; 5081da177e4SLinus Torvalds unsigned int pinctl; 5091da177e4SLinus Torvalds char *label; 5101da177e4SLinus Torvalds const char *type; 5111da177e4SLinus Torvalds 5121da177e4SLinus Torvalds if (node->checked) 5131da177e4SLinus Torvalds return 0; 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds node->checked = 1; 5161da177e4SLinus Torvalds if (node->type != AC_WID_PIN) { 5171da177e4SLinus Torvalds for (i = 0; i < node->nconns; i++) { 5181da177e4SLinus Torvalds struct hda_gnode *child; 5191da177e4SLinus Torvalds child = hda_get_node(spec, node->conn_list[i]); 5201da177e4SLinus Torvalds if (! child) 5211da177e4SLinus Torvalds continue; 5221da177e4SLinus Torvalds err = parse_adc_sub_nodes(codec, spec, child); 5231da177e4SLinus Torvalds if (err < 0) 5241da177e4SLinus Torvalds return err; 5251da177e4SLinus Torvalds if (err > 0) { 5261da177e4SLinus Torvalds /* found one, 5271da177e4SLinus Torvalds * select the path, unmute both input and output 5281da177e4SLinus Torvalds */ 5291da177e4SLinus Torvalds if (node->nconns > 1) 5301da177e4SLinus Torvalds select_input_connection(codec, node, i); 5311da177e4SLinus Torvalds unmute_input(codec, node, i); 5321da177e4SLinus Torvalds unmute_output(codec, node); 5331da177e4SLinus Torvalds return err; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds return 0; 5371da177e4SLinus Torvalds } 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds /* input capable? */ 5401da177e4SLinus Torvalds if (! (node->pin_caps & AC_PINCAP_IN)) 5411da177e4SLinus Torvalds return 0; 5421da177e4SLinus Torvalds 54397ec558aSTakashi Iwai if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) 54497ec558aSTakashi Iwai return 0; /* unconnected */ 54597ec558aSTakashi Iwai 5461da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_DIGITAL) 5471da177e4SLinus Torvalds return 0; /* skip SPDIF */ 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { 5501da177e4SLinus Torvalds snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); 5511da177e4SLinus Torvalds return -EINVAL; 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds pinctl = AC_PINCTL_IN_EN; 5551da177e4SLinus Torvalds /* create a proper capture source label */ 5561da177e4SLinus Torvalds type = get_input_type(node, &pinctl); 5571da177e4SLinus Torvalds if (! type) { 5581da177e4SLinus Torvalds /* input as default? */ 5591da177e4SLinus Torvalds if (! (node->pin_ctl & AC_PINCTL_IN_EN)) 5601da177e4SLinus Torvalds return 0; 5611da177e4SLinus Torvalds type = "Input"; 5621da177e4SLinus Torvalds } 5631da177e4SLinus Torvalds label = spec->cap_labels[spec->input_mux.num_items]; 5641da177e4SLinus Torvalds strcpy(label, type); 5651da177e4SLinus Torvalds spec->input_mux.items[spec->input_mux.num_items].label = label; 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds /* unmute the PIN external input */ 5681da177e4SLinus Torvalds unmute_input(codec, node, 0); /* index = 0? */ 5691da177e4SLinus Torvalds /* set PIN-In enable */ 57082beb8fdSTakashi Iwai snd_hda_codec_write_cache(codec, node->nid, 0, 57182beb8fdSTakashi Iwai AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds return 1; /* found */ 5741da177e4SLinus Torvalds } 5751da177e4SLinus Torvalds 576071c73adSTakashi Iwai /* add a capture source element */ 577071c73adSTakashi Iwai static void add_cap_src(struct hda_gspec *spec, int idx) 578071c73adSTakashi Iwai { 579071c73adSTakashi Iwai struct hda_input_mux_item *csrc; 580071c73adSTakashi Iwai char *buf; 581071c73adSTakashi Iwai int num, ocap; 582071c73adSTakashi Iwai 583071c73adSTakashi Iwai num = spec->input_mux.num_items; 584071c73adSTakashi Iwai csrc = &spec->input_mux.items[num]; 585071c73adSTakashi Iwai buf = spec->cap_labels[num]; 586071c73adSTakashi Iwai for (ocap = 0; ocap < num; ocap++) { 587071c73adSTakashi Iwai if (! strcmp(buf, spec->cap_labels[ocap])) { 588071c73adSTakashi Iwai /* same label already exists, 589071c73adSTakashi Iwai * put the index number to be unique 590071c73adSTakashi Iwai */ 591071c73adSTakashi Iwai sprintf(buf, "%s %d", spec->cap_labels[ocap], num); 592071c73adSTakashi Iwai break; 593071c73adSTakashi Iwai } 594071c73adSTakashi Iwai } 595071c73adSTakashi Iwai csrc->index = idx; 596071c73adSTakashi Iwai spec->input_mux.num_items++; 597071c73adSTakashi Iwai } 598071c73adSTakashi Iwai 5991da177e4SLinus Torvalds /* 6001da177e4SLinus Torvalds * parse input 6011da177e4SLinus Torvalds */ 6021da177e4SLinus Torvalds static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) 6031da177e4SLinus Torvalds { 6041da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 6051da177e4SLinus Torvalds struct hda_gnode *node; 6061da177e4SLinus Torvalds int i, err; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds snd_printdd("AUD_IN = %x\n", adc_node->nid); 6091da177e4SLinus Torvalds clear_check_flags(spec); 6101da177e4SLinus Torvalds 6111da177e4SLinus Torvalds // awk added - fixed no recording due to muted widget 6121da177e4SLinus Torvalds unmute_input(codec, adc_node, 0); 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds /* 6151da177e4SLinus Torvalds * check each connection of the ADC 6161da177e4SLinus Torvalds * if it reaches to a proper input PIN, add the path as the 6171da177e4SLinus Torvalds * input path. 6181da177e4SLinus Torvalds */ 619071c73adSTakashi Iwai /* first, check the direct connections to PIN widgets */ 6201da177e4SLinus Torvalds for (i = 0; i < adc_node->nconns; i++) { 6211da177e4SLinus Torvalds node = hda_get_node(spec, adc_node->conn_list[i]); 622071c73adSTakashi Iwai if (node && node->type == AC_WID_PIN) { 6231da177e4SLinus Torvalds err = parse_adc_sub_nodes(codec, spec, node); 6241da177e4SLinus Torvalds if (err < 0) 6251da177e4SLinus Torvalds return err; 626071c73adSTakashi Iwai else if (err > 0) 627071c73adSTakashi Iwai add_cap_src(spec, i); 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds } 630071c73adSTakashi Iwai /* ... then check the rests, more complicated connections */ 631071c73adSTakashi Iwai for (i = 0; i < adc_node->nconns; i++) { 632071c73adSTakashi Iwai node = hda_get_node(spec, adc_node->conn_list[i]); 633071c73adSTakashi Iwai if (node && node->type != AC_WID_PIN) { 634071c73adSTakashi Iwai err = parse_adc_sub_nodes(codec, spec, node); 635071c73adSTakashi Iwai if (err < 0) 636071c73adSTakashi Iwai return err; 637071c73adSTakashi Iwai else if (err > 0) 638071c73adSTakashi Iwai add_cap_src(spec, i); 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds } 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds if (! spec->input_mux.num_items) 6431da177e4SLinus Torvalds return 0; /* no input path found... */ 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); 6461da177e4SLinus Torvalds for (i = 0; i < spec->input_mux.num_items; i++) 6471da177e4SLinus Torvalds snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, 6481da177e4SLinus Torvalds spec->input_mux.items[i].index); 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds spec->adc_node = adc_node; 6511da177e4SLinus Torvalds return 1; 6521da177e4SLinus Torvalds } 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds /* 6551da177e4SLinus Torvalds * parse input 6561da177e4SLinus Torvalds */ 6571da177e4SLinus Torvalds static int parse_input(struct hda_codec *codec) 6581da177e4SLinus Torvalds { 6591da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 6601da177e4SLinus Torvalds struct hda_gnode *node; 6611da177e4SLinus Torvalds int err; 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds /* 6641da177e4SLinus Torvalds * At first we look for an audio input widget. 6651da177e4SLinus Torvalds * If it reaches to certain input PINs, we take it as the 6661da177e4SLinus Torvalds * input path. 6671da177e4SLinus Torvalds */ 66833206e86SMatthias Kaehlcke list_for_each_entry(node, &spec->nid_list, list) { 6691da177e4SLinus Torvalds if (node->wid_caps & AC_WCAP_DIGITAL) 6701da177e4SLinus Torvalds continue; /* skip SPDIF */ 6711da177e4SLinus Torvalds if (node->type == AC_WID_AUD_IN) { 6721da177e4SLinus Torvalds err = parse_input_path(codec, node); 6731da177e4SLinus Torvalds if (err < 0) 6741da177e4SLinus Torvalds return err; 6751da177e4SLinus Torvalds else if (err > 0) 6761da177e4SLinus Torvalds return 0; 6771da177e4SLinus Torvalds } 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds snd_printd("hda_generic: no proper input path found\n"); 6801da177e4SLinus Torvalds return 0; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds 683cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 684cb53c626STakashi Iwai static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, 685cb53c626STakashi Iwai int dir, int idx) 686cb53c626STakashi Iwai { 687cb53c626STakashi Iwai struct hda_gspec *spec = codec->spec; 688cb53c626STakashi Iwai struct hda_amp_list *p; 689cb53c626STakashi Iwai 690cb53c626STakashi Iwai if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { 691cb53c626STakashi Iwai snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); 692cb53c626STakashi Iwai return; 693cb53c626STakashi Iwai } 694cb53c626STakashi Iwai p = &spec->loopback_list[spec->num_loopbacks++]; 695cb53c626STakashi Iwai p->nid = nid; 696cb53c626STakashi Iwai p->dir = dir; 697cb53c626STakashi Iwai p->idx = idx; 698cb53c626STakashi Iwai spec->loopback.amplist = spec->loopback_list; 699cb53c626STakashi Iwai } 700cb53c626STakashi Iwai #else 701cb53c626STakashi Iwai #define add_input_loopback(codec,nid,dir,idx) 702cb53c626STakashi Iwai #endif 703cb53c626STakashi Iwai 7041da177e4SLinus Torvalds /* 7051da177e4SLinus Torvalds * create mixer controls if possible 7061da177e4SLinus Torvalds */ 7071da177e4SLinus Torvalds static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, 708cb53c626STakashi Iwai unsigned int index, const char *type, 709cb53c626STakashi Iwai const char *dir_sfx, int is_loopback) 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds char name[32]; 7121da177e4SLinus Torvalds int err; 7131da177e4SLinus Torvalds int created = 0; 714c8b6bf9bSTakashi Iwai struct snd_kcontrol_new knew; 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds if (type) 7171da177e4SLinus Torvalds sprintf(name, "%s %s Switch", type, dir_sfx); 7181da177e4SLinus Torvalds else 7191da177e4SLinus Torvalds sprintf(name, "%s Switch", dir_sfx); 7201da177e4SLinus Torvalds if ((node->wid_caps & AC_WCAP_IN_AMP) && 7211da177e4SLinus Torvalds (node->amp_in_caps & AC_AMPCAP_MUTE)) { 722c8b6bf9bSTakashi Iwai knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); 723cb53c626STakashi Iwai if (is_loopback) 724cb53c626STakashi Iwai add_input_loopback(codec, node->nid, HDA_INPUT, index); 7251da177e4SLinus Torvalds snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); 726d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); 727d13bd412STakashi Iwai if (err < 0) 7281da177e4SLinus Torvalds return err; 7291da177e4SLinus Torvalds created = 1; 7301da177e4SLinus Torvalds } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && 7311da177e4SLinus Torvalds (node->amp_out_caps & AC_AMPCAP_MUTE)) { 732c8b6bf9bSTakashi Iwai knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); 733cb53c626STakashi Iwai if (is_loopback) 734cb53c626STakashi Iwai add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); 7351da177e4SLinus Torvalds snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); 736d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); 737d13bd412STakashi Iwai if (err < 0) 7381da177e4SLinus Torvalds return err; 7391da177e4SLinus Torvalds created = 1; 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds if (type) 7431da177e4SLinus Torvalds sprintf(name, "%s %s Volume", type, dir_sfx); 7441da177e4SLinus Torvalds else 7451da177e4SLinus Torvalds sprintf(name, "%s Volume", dir_sfx); 7461da177e4SLinus Torvalds if ((node->wid_caps & AC_WCAP_IN_AMP) && 7471da177e4SLinus Torvalds (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { 748c8b6bf9bSTakashi Iwai knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); 7491da177e4SLinus Torvalds snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); 750d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); 751d13bd412STakashi Iwai if (err < 0) 7521da177e4SLinus Torvalds return err; 7531da177e4SLinus Torvalds created = 1; 7541da177e4SLinus Torvalds } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && 7551da177e4SLinus Torvalds (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { 756c8b6bf9bSTakashi Iwai knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); 7571da177e4SLinus Torvalds snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); 758d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); 759d13bd412STakashi Iwai if (err < 0) 7601da177e4SLinus Torvalds return err; 7611da177e4SLinus Torvalds created = 1; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds return created; 7651da177e4SLinus Torvalds } 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds /* 7681da177e4SLinus Torvalds * check whether the controls with the given name and direction suffix already exist 7691da177e4SLinus Torvalds */ 7701da177e4SLinus Torvalds static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) 7711da177e4SLinus Torvalds { 772c8b6bf9bSTakashi Iwai struct snd_ctl_elem_id id; 7731da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 7741da177e4SLinus Torvalds sprintf(id.name, "%s %s Volume", type, dir); 7751da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7761da177e4SLinus Torvalds if (snd_ctl_find_id(codec->bus->card, &id)) 7771da177e4SLinus Torvalds return 1; 7781da177e4SLinus Torvalds sprintf(id.name, "%s %s Switch", type, dir); 7791da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7801da177e4SLinus Torvalds if (snd_ctl_find_id(codec->bus->card, &id)) 7811da177e4SLinus Torvalds return 1; 7821da177e4SLinus Torvalds return 0; 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds /* 7861da177e4SLinus Torvalds * build output mixer controls 7871da177e4SLinus Torvalds */ 788a7da6ce5STakashi Iwai static int create_output_mixers(struct hda_codec *codec, const char **names) 789a7da6ce5STakashi Iwai { 790a7da6ce5STakashi Iwai struct hda_gspec *spec = codec->spec; 791a7da6ce5STakashi Iwai int i, err; 792a7da6ce5STakashi Iwai 793a7da6ce5STakashi Iwai for (i = 0; i < spec->pcm_vol_nodes; i++) { 794a7da6ce5STakashi Iwai err = create_mixer(codec, spec->pcm_vol[i].node, 795a7da6ce5STakashi Iwai spec->pcm_vol[i].index, 796cb53c626STakashi Iwai names[i], "Playback", 0); 797a7da6ce5STakashi Iwai if (err < 0) 798a7da6ce5STakashi Iwai return err; 799a7da6ce5STakashi Iwai } 800a7da6ce5STakashi Iwai return 0; 801a7da6ce5STakashi Iwai } 802a7da6ce5STakashi Iwai 8031da177e4SLinus Torvalds static int build_output_controls(struct hda_codec *codec) 8041da177e4SLinus Torvalds { 8051da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 806a7da6ce5STakashi Iwai static const char *types_speaker[] = { "Speaker", "Headphone" }; 807a7da6ce5STakashi Iwai static const char *types_line[] = { "Front", "Headphone" }; 8081da177e4SLinus Torvalds 809a7da6ce5STakashi Iwai switch (spec->pcm_vol_nodes) { 810a7da6ce5STakashi Iwai case 1: 811a7da6ce5STakashi Iwai return create_mixer(codec, spec->pcm_vol[0].node, 812a7da6ce5STakashi Iwai spec->pcm_vol[0].index, 813cb53c626STakashi Iwai "Master", "Playback", 0); 814a7da6ce5STakashi Iwai case 2: 815a7da6ce5STakashi Iwai if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) 816a7da6ce5STakashi Iwai return create_output_mixers(codec, types_speaker); 817a7da6ce5STakashi Iwai else 818a7da6ce5STakashi Iwai return create_output_mixers(codec, types_line); 81997ec558aSTakashi Iwai } 8201da177e4SLinus Torvalds return 0; 8211da177e4SLinus Torvalds } 8221da177e4SLinus Torvalds 8231da177e4SLinus Torvalds /* create capture volume/switch */ 8241da177e4SLinus Torvalds static int build_input_controls(struct hda_codec *codec) 8251da177e4SLinus Torvalds { 8261da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 8271da177e4SLinus Torvalds struct hda_gnode *adc_node = spec->adc_node; 828071c73adSTakashi Iwai int i, err; 829c8b6bf9bSTakashi Iwai static struct snd_kcontrol_new cap_sel = { 8301da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8311da177e4SLinus Torvalds .name = "Capture Source", 8321da177e4SLinus Torvalds .info = capture_source_info, 8331da177e4SLinus Torvalds .get = capture_source_get, 8341da177e4SLinus Torvalds .put = capture_source_put, 8351da177e4SLinus Torvalds }; 836071c73adSTakashi Iwai 837071c73adSTakashi Iwai if (! adc_node || ! spec->input_mux.num_items) 838071c73adSTakashi Iwai return 0; /* not found */ 839071c73adSTakashi Iwai 8401da177e4SLinus Torvalds spec->cur_cap_src = 0; 841071c73adSTakashi Iwai select_input_connection(codec, adc_node, 842071c73adSTakashi Iwai spec->input_mux.items[0].index); 843071c73adSTakashi Iwai 844071c73adSTakashi Iwai /* create capture volume and switch controls if the ADC has an amp */ 845071c73adSTakashi Iwai /* do we have only a single item? */ 846071c73adSTakashi Iwai if (spec->input_mux.num_items == 1) { 847071c73adSTakashi Iwai err = create_mixer(codec, adc_node, 848071c73adSTakashi Iwai spec->input_mux.items[0].index, 849cb53c626STakashi Iwai NULL, "Capture", 0); 850071c73adSTakashi Iwai if (err < 0) 851071c73adSTakashi Iwai return err; 852071c73adSTakashi Iwai return 0; 8531da177e4SLinus Torvalds } 854071c73adSTakashi Iwai 855071c73adSTakashi Iwai /* create input MUX if multiple sources are available */ 856d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); 857d13bd412STakashi Iwai if (err < 0) 858071c73adSTakashi Iwai return err; 859071c73adSTakashi Iwai 860071c73adSTakashi Iwai /* no volume control? */ 861071c73adSTakashi Iwai if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || 862071c73adSTakashi Iwai ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) 863071c73adSTakashi Iwai return 0; 864071c73adSTakashi Iwai 865071c73adSTakashi Iwai for (i = 0; i < spec->input_mux.num_items; i++) { 866071c73adSTakashi Iwai struct snd_kcontrol_new knew; 867071c73adSTakashi Iwai char name[32]; 868071c73adSTakashi Iwai sprintf(name, "%s Capture Volume", 869071c73adSTakashi Iwai spec->input_mux.items[i].label); 870071c73adSTakashi Iwai knew = (struct snd_kcontrol_new) 871071c73adSTakashi Iwai HDA_CODEC_VOLUME(name, adc_node->nid, 872071c73adSTakashi Iwai spec->input_mux.items[i].index, 873071c73adSTakashi Iwai HDA_INPUT); 874d13bd412STakashi Iwai err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); 875d13bd412STakashi Iwai if (err < 0) 876071c73adSTakashi Iwai return err; 877071c73adSTakashi Iwai } 878071c73adSTakashi Iwai 8791da177e4SLinus Torvalds return 0; 8801da177e4SLinus Torvalds } 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds /* 8841da177e4SLinus Torvalds * parse the nodes recursively until reach to the output PIN. 8851da177e4SLinus Torvalds * 8861da177e4SLinus Torvalds * returns 0 - if not found, 8871da177e4SLinus Torvalds * 1 - if found, but no mixer is created 8881da177e4SLinus Torvalds * 2 - if found and mixer was already created, (just skip) 8891da177e4SLinus Torvalds * a negative error code 8901da177e4SLinus Torvalds */ 8911da177e4SLinus Torvalds static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, 8921da177e4SLinus Torvalds struct hda_gnode *node, struct hda_gnode *dest_node, 8931da177e4SLinus Torvalds const char *type) 8941da177e4SLinus Torvalds { 8951da177e4SLinus Torvalds int i, err; 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds if (node->checked) 8981da177e4SLinus Torvalds return 0; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds node->checked = 1; 9011da177e4SLinus Torvalds if (node == dest_node) { 9021da177e4SLinus Torvalds /* loopback connection found */ 9031da177e4SLinus Torvalds return 1; 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds for (i = 0; i < node->nconns; i++) { 9071da177e4SLinus Torvalds struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); 9081da177e4SLinus Torvalds if (! child) 9091da177e4SLinus Torvalds continue; 9101da177e4SLinus Torvalds err = parse_loopback_path(codec, spec, child, dest_node, type); 9111da177e4SLinus Torvalds if (err < 0) 9121da177e4SLinus Torvalds return err; 9131da177e4SLinus Torvalds else if (err >= 1) { 9141da177e4SLinus Torvalds if (err == 1) { 915cb53c626STakashi Iwai err = create_mixer(codec, node, i, type, 916cb53c626STakashi Iwai "Playback", 1); 9171da177e4SLinus Torvalds if (err < 0) 9181da177e4SLinus Torvalds return err; 9191da177e4SLinus Torvalds if (err > 0) 9201da177e4SLinus Torvalds return 2; /* ok, created */ 9211da177e4SLinus Torvalds /* not created, maybe in the lower path */ 9221da177e4SLinus Torvalds err = 1; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds /* connect and unmute */ 9251da177e4SLinus Torvalds if (node->nconns > 1) 9261da177e4SLinus Torvalds select_input_connection(codec, node, i); 9271da177e4SLinus Torvalds unmute_input(codec, node, i); 9281da177e4SLinus Torvalds unmute_output(codec, node); 9291da177e4SLinus Torvalds return err; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds } 9321da177e4SLinus Torvalds return 0; 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds /* 9361da177e4SLinus Torvalds * parse the tree and build the loopback controls 9371da177e4SLinus Torvalds */ 9381da177e4SLinus Torvalds static int build_loopback_controls(struct hda_codec *codec) 9391da177e4SLinus Torvalds { 9401da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 9411da177e4SLinus Torvalds struct hda_gnode *node; 9421da177e4SLinus Torvalds int err; 9431da177e4SLinus Torvalds const char *type; 9441da177e4SLinus Torvalds 94597ec558aSTakashi Iwai if (! spec->out_pin_node[0]) 9461da177e4SLinus Torvalds return 0; 9471da177e4SLinus Torvalds 94833206e86SMatthias Kaehlcke list_for_each_entry(node, &spec->nid_list, list) { 9491da177e4SLinus Torvalds if (node->type != AC_WID_PIN) 9501da177e4SLinus Torvalds continue; 9511da177e4SLinus Torvalds /* input capable? */ 9521da177e4SLinus Torvalds if (! (node->pin_caps & AC_PINCAP_IN)) 9531da177e4SLinus Torvalds return 0; 9541da177e4SLinus Torvalds type = get_input_type(node, NULL); 9551da177e4SLinus Torvalds if (type) { 9561da177e4SLinus Torvalds if (check_existing_control(codec, type, "Playback")) 9571da177e4SLinus Torvalds continue; 9581da177e4SLinus Torvalds clear_check_flags(spec); 95997ec558aSTakashi Iwai err = parse_loopback_path(codec, spec, 96097ec558aSTakashi Iwai spec->out_pin_node[0], 9611da177e4SLinus Torvalds node, type); 9621da177e4SLinus Torvalds if (err < 0) 9631da177e4SLinus Torvalds return err; 9641da177e4SLinus Torvalds if (! err) 9651da177e4SLinus Torvalds continue; 9661da177e4SLinus Torvalds } 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds return 0; 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds /* 9721da177e4SLinus Torvalds * build mixer controls 9731da177e4SLinus Torvalds */ 9741da177e4SLinus Torvalds static int build_generic_controls(struct hda_codec *codec) 9751da177e4SLinus Torvalds { 9761da177e4SLinus Torvalds int err; 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds if ((err = build_input_controls(codec)) < 0 || 9791da177e4SLinus Torvalds (err = build_output_controls(codec)) < 0 || 9801da177e4SLinus Torvalds (err = build_loopback_controls(codec)) < 0) 9811da177e4SLinus Torvalds return err; 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds return 0; 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds /* 9871da177e4SLinus Torvalds * PCM 9881da177e4SLinus Torvalds */ 9891da177e4SLinus Torvalds static struct hda_pcm_stream generic_pcm_playback = { 9901da177e4SLinus Torvalds .substreams = 1, 9911da177e4SLinus Torvalds .channels_min = 2, 9921da177e4SLinus Torvalds .channels_max = 2, 9931da177e4SLinus Torvalds }; 9941da177e4SLinus Torvalds 99597ec558aSTakashi Iwai static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo, 99697ec558aSTakashi Iwai struct hda_codec *codec, 99797ec558aSTakashi Iwai unsigned int stream_tag, 99897ec558aSTakashi Iwai unsigned int format, 99997ec558aSTakashi Iwai struct snd_pcm_substream *substream) 100097ec558aSTakashi Iwai { 100197ec558aSTakashi Iwai struct hda_gspec *spec = codec->spec; 100297ec558aSTakashi Iwai 100397ec558aSTakashi Iwai snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); 100497ec558aSTakashi Iwai snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 100597ec558aSTakashi Iwai stream_tag, 0, format); 100697ec558aSTakashi Iwai return 0; 100797ec558aSTakashi Iwai } 100897ec558aSTakashi Iwai 100997ec558aSTakashi Iwai static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo, 101097ec558aSTakashi Iwai struct hda_codec *codec, 101197ec558aSTakashi Iwai struct snd_pcm_substream *substream) 101297ec558aSTakashi Iwai { 101397ec558aSTakashi Iwai struct hda_gspec *spec = codec->spec; 101497ec558aSTakashi Iwai 1015888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, hinfo->nid); 1016888afa15STakashi Iwai snd_hda_codec_cleanup_stream(codec, spec->dac_node[1]->nid); 101797ec558aSTakashi Iwai return 0; 101897ec558aSTakashi Iwai } 101997ec558aSTakashi Iwai 10201da177e4SLinus Torvalds static int build_generic_pcms(struct hda_codec *codec) 10211da177e4SLinus Torvalds { 10221da177e4SLinus Torvalds struct hda_gspec *spec = codec->spec; 10231da177e4SLinus Torvalds struct hda_pcm *info = &spec->pcm_rec; 10241da177e4SLinus Torvalds 102597ec558aSTakashi Iwai if (! spec->dac_node[0] && ! spec->adc_node) { 10261da177e4SLinus Torvalds snd_printd("hda_generic: no PCM found\n"); 10271da177e4SLinus Torvalds return 0; 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 10301da177e4SLinus Torvalds codec->num_pcms = 1; 10311da177e4SLinus Torvalds codec->pcm_info = info; 10321da177e4SLinus Torvalds 10331da177e4SLinus Torvalds info->name = "HDA Generic"; 103497ec558aSTakashi Iwai if (spec->dac_node[0]) { 10351da177e4SLinus Torvalds info->stream[0] = generic_pcm_playback; 103697ec558aSTakashi Iwai info->stream[0].nid = spec->dac_node[0]->nid; 103797ec558aSTakashi Iwai if (spec->dac_node[1]) { 103897ec558aSTakashi Iwai info->stream[0].ops.prepare = generic_pcm2_prepare; 103997ec558aSTakashi Iwai info->stream[0].ops.cleanup = generic_pcm2_cleanup; 104097ec558aSTakashi Iwai } 10411da177e4SLinus Torvalds } 10421da177e4SLinus Torvalds if (spec->adc_node) { 10431da177e4SLinus Torvalds info->stream[1] = generic_pcm_playback; 10441da177e4SLinus Torvalds info->stream[1].nid = spec->adc_node->nid; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds return 0; 10481da177e4SLinus Torvalds } 10491da177e4SLinus Torvalds 1050cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 1051cb53c626STakashi Iwai static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) 1052cb53c626STakashi Iwai { 1053cb53c626STakashi Iwai struct hda_gspec *spec = codec->spec; 1054cb53c626STakashi Iwai return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); 1055cb53c626STakashi Iwai } 1056cb53c626STakashi Iwai #endif 1057cb53c626STakashi Iwai 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds /* 10601da177e4SLinus Torvalds */ 10611da177e4SLinus Torvalds static struct hda_codec_ops generic_patch_ops = { 10621da177e4SLinus Torvalds .build_controls = build_generic_controls, 10631da177e4SLinus Torvalds .build_pcms = build_generic_pcms, 10641da177e4SLinus Torvalds .free = snd_hda_generic_free, 1065cb53c626STakashi Iwai #ifdef CONFIG_SND_HDA_POWER_SAVE 1066cb53c626STakashi Iwai .check_power_status = generic_check_power_status, 1067cb53c626STakashi Iwai #endif 10681da177e4SLinus Torvalds }; 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds /* 10711da177e4SLinus Torvalds * the generic parser 10721da177e4SLinus Torvalds */ 10731da177e4SLinus Torvalds int snd_hda_parse_generic_codec(struct hda_codec *codec) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds struct hda_gspec *spec; 10761da177e4SLinus Torvalds int err; 10771da177e4SLinus Torvalds 107884802f0dSSasha Khapyorsky if(!codec->afg) 107984802f0dSSasha Khapyorsky return 0; 1080673b683aSSasha Khapyorsky 1081e560d8d8STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 10821da177e4SLinus Torvalds if (spec == NULL) { 10831da177e4SLinus Torvalds printk(KERN_ERR "hda_generic: can't allocate spec\n"); 10841da177e4SLinus Torvalds return -ENOMEM; 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds codec->spec = spec; 10871da177e4SLinus Torvalds INIT_LIST_HEAD(&spec->nid_list); 10881da177e4SLinus Torvalds 10891da177e4SLinus Torvalds if ((err = build_afg_tree(codec)) < 0) 10901da177e4SLinus Torvalds goto error; 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds if ((err = parse_input(codec)) < 0 || 10931da177e4SLinus Torvalds (err = parse_output(codec)) < 0) 10941da177e4SLinus Torvalds goto error; 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds codec->patch_ops = generic_patch_ops; 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds return 0; 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds error: 11011da177e4SLinus Torvalds snd_hda_generic_free(codec); 11021da177e4SLinus Torvalds return err; 11031da177e4SLinus Torvalds } 1104