📄 patch_sigmatel.c
字号:
return 0;}static int check_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid){ if (is_in_dac_nids(spec, nid)) return 1; if (spec->multiout.hp_nid == nid) return 1; return 0;}static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid){ if (!spec->multiout.hp_nid) spec->multiout.hp_nid = nid; else if (spec->multiout.num_dacs > 4) { printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); return 1; } else { spec->multiout.dac_nids[spec->multiout.num_dacs] = nid; spec->multiout.num_dacs++; } return 0;}/* add playback controls for Speaker and HP outputs */static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; hda_nid_t nid; int i, old_num_dacs, err; old_num_dacs = spec->multiout.num_dacs; for (i = 0; i < cfg->hp_outs; i++) { unsigned int wid_caps = get_wcaps(codec, cfg->hp_pins[i]); if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; nid = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; if (check_in_dac_nids(spec, nid)) nid = 0; if (! nid) continue; add_spec_dacs(spec, nid); } for (i = 0; i < cfg->speaker_outs; i++) { nid = snd_hda_codec_read(codec, cfg->speaker_pins[i], 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; if (check_in_dac_nids(spec, nid)) nid = 0; if (! nid) continue; add_spec_dacs(spec, nid); } for (i = 0; i < cfg->line_outs; i++) { nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; if (check_in_dac_nids(spec, nid)) nid = 0; if (! nid) continue; add_spec_dacs(spec, nid); } for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) { static const char *pfxs[] = { "Speaker", "External Speaker", "Speaker2", }; err = create_controls(spec, pfxs[i - old_num_dacs], spec->multiout.dac_nids[i], 3); if (err < 0) return err; } if (spec->multiout.hp_nid) { const char *pfx; if (old_num_dacs == spec->multiout.num_dacs) pfx = "Master"; else pfx = "Headphone"; err = create_controls(spec, pfx, spec->multiout.hp_nid, 3); if (err < 0) return err; } return 0;}/* labels for dmic mux inputs */static const char *stac92xx_dmic_labels[5] = { "Analog Inputs", "Digital Mic 1", "Digital Mic 2", "Digital Mic 3", "Digital Mic 4"};/* create playback/capture controls for input pins on dmic capable codecs */static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *dimux = &spec->private_dimux; hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; int i, j; dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; dimux->items[dimux->num_items].index = 0; dimux->num_items++; for (i = 0; i < spec->num_dmics; i++) { int index; int num_cons; unsigned int def_conf; def_conf = snd_hda_codec_read(codec, spec->dmic_nids[i], 0, AC_VERB_GET_CONFIG_DEFAULT, 0); if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) continue; num_cons = snd_hda_get_connections(codec, spec->dmux_nid, con_lst, HDA_MAX_NUM_INPUTS); for (j = 0; j < num_cons; j++) if (con_lst[j] == spec->dmic_nids[i]) { index = j; goto found; } continue;found: dimux->items[dimux->num_items].label = stac92xx_dmic_labels[dimux->num_items]; dimux->items[dimux->num_items].index = index; dimux->num_items++; } return 0;}/* create playback/capture controls for input pins */static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *imux = &spec->private_imux; hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; int i, j, k; for (i = 0; i < AUTO_PIN_LAST; i++) { int index; if (!cfg->input_pins[i]) continue; index = -1; for (j = 0; j < spec->num_muxes; j++) { int num_cons; num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS); for (k = 0; k < num_cons; k++) if (con_lst[k] == cfg->input_pins[i]) { index = k; goto found; } } continue; found: imux->items[imux->num_items].label = auto_pin_cfg_labels[i]; imux->items[imux->num_items].index = index; imux->num_items++; } if (imux->num_items) { /* * Set the current input for the muxes. * The STAC9221 has two input muxes with identical source * NID lists. Hopefully this won't get confused. */ for (i = 0; i < spec->num_muxes; i++) { snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, AC_VERB_SET_CONNECT_SEL, imux->items[0].index); } } return 0;}static void stac92xx_auto_init_multi_out(struct hda_codec *codec){ struct sigmatel_spec *spec = codec->spec; int i; for (i = 0; i < spec->autocfg.line_outs; i++) { hda_nid_t nid = spec->autocfg.line_out_pins[i]; stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); }}static void stac92xx_auto_init_hp_out(struct hda_codec *codec){ struct sigmatel_spec *spec = codec->spec; int i; for (i = 0; i < spec->autocfg.hp_outs; i++) { hda_nid_t pin; pin = spec->autocfg.hp_pins[i]; if (pin) /* connect to front */ stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); } for (i = 0; i < spec->autocfg.speaker_outs; i++) { hda_nid_t pin; pin = spec->autocfg.speaker_pins[i]; if (pin) /* connect to front */ stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); }}static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out, hda_nid_t dig_in){ struct sigmatel_spec *spec = codec->spec; int err; if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, spec->dmic_nids)) < 0) return err; if (! spec->autocfg.line_outs) return 0; /* can't find valid pin config */ if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) return err; if (spec->multiout.num_dacs == 0) if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err; err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); if (err < 0) return err; err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); if (err < 0) return err; err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); if (err < 0) return err; if (spec->num_dmics > 0) if ((err = stac92xx_auto_create_dmic_input_ctls(codec, &spec->autocfg)) < 0) return err; spec->multiout.max_channels = spec->multiout.num_dacs * 2; if (spec->multiout.max_channels > 2) spec->surr_switch = 1; if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = dig_out; if (spec->autocfg.dig_in_pin) spec->dig_in_nid = dig_in; if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; return 1;}/* add playback controls for HP output */static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; hda_nid_t pin = cfg->hp_pins[0]; unsigned int wid_caps; if (! pin) return 0; wid_caps = get_wcaps(codec, pin); if (wid_caps & AC_WCAP_UNSOL_CAP) spec->hp_detect = 1; return 0;}/* add playback controls for LFE output */static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; int err; hda_nid_t lfe_pin = 0x0; int i; /* * search speaker outs and line outs for a mono speaker pin * with an amp. If one is found, add LFE controls * for it. */ for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { hda_nid_t pin = spec->autocfg.speaker_pins[i]; unsigned long wcaps = get_wcaps(codec, pin); wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); if (wcaps == AC_WCAP_OUT_AMP) /* found a mono speaker with an amp, must be lfe */ lfe_pin = pin; } /* if speaker_outs is 0, then speakers may be in line_outs */ if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { hda_nid_t pin = spec->autocfg.line_out_pins[i]; unsigned long cfg; cfg = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONFIG_DEFAULT, 0x00); if (get_defcfg_device(cfg) == AC_JACK_SPEAKER) { unsigned long wcaps = get_wcaps(codec, pin); wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); if (wcaps == AC_WCAP_OUT_AMP) /* found a mono speaker with an amp, must be lfe */ lfe_pin = pin; } } } if (lfe_pin) { err = create_controls(spec, "LFE", lfe_pin, 1); if (err < 0) return err; } return 0;}static int stac9200_parse_auto_config(struct hda_codec *codec){ struct sigmatel_spec *spec = codec->spec; int err; if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) return err; if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) return err; if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) return err; if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) return err; if (spec->autocfg.dig_out_pin) spec->multiout.dig_out_nid = 0x05; if (spec->autocfg.dig_in_pin) spec->dig_in_nid = 0x04; if (spec->kctl_alloc) spec->mixers[spec->num_mixers++] = spec->kctl_alloc; spec->input_mux = &spec->private_imux; spec->dinput_mux = &spec->private_dimux; return 1;}/* * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a * funky external mute control using GPIO pins. */static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted){ unsigned int gpiostate, gpiomask, gpiodir; gpiostate = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_DATA, 0); if (!muted) gpiostate |= (1 << pin); else gpiostate &= ~(1 << pin); gpiomask = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_MASK, 0); gpiomask |= (1 << pin); gpiodir = snd_hda_codec_read(codec, codec->afg, 0, AC_VERB_GET_GPIO_DIRECTION, 0); gpiodir |= (1 << pin); /* AppleHDA seems to do this -- WTF is this verb?? */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_MASK, gpiomask); snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DIRECTION, gpiodir); msleep(1); snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA, gpiostate);}static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, unsigned int event){ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, (AC_USRSP_EN | event));}static int stac92xx_init(struct hda_codec *codec){ struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; int i; snd_hda_sequence_write(codec, spec->init); /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ for (i = 0; i < cfg->hp_outs; i++) enable_pin_detect(codec, cfg->hp_pins[i], STAC_HP_EVENT); /* force to enable the first line-out; the others are set up * in unsol_event */ stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); stac92xx_auto_init_hp_out(codec); /* fake event to set up pins */ codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -