📄 patch_sigmatel.c
字号:
struct sigmatel_spec *spec = codec->spec; return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);}/* * Digital playback callbacks */static int stac92xx_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream){ struct sigmatel_spec *spec = codec->spec; return snd_hda_multi_out_dig_open(codec, &spec->multiout);}static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream){ struct sigmatel_spec *spec = codec->spec; return snd_hda_multi_out_dig_close(codec, &spec->multiout);}/* * Analog capture callbacks */static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream){ struct sigmatel_spec *spec = codec->spec; snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], stream_tag, 0, format); return 0;}static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream){ struct sigmatel_spec *spec = codec->spec; snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); return 0;}static struct hda_pcm_stream stac92xx_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in stac92xx_build_pcms */ .ops = { .open = stac92xx_dig_playback_pcm_open, .close = stac92xx_dig_playback_pcm_close },};static struct hda_pcm_stream stac92xx_pcm_digital_capture = { .substreams = 1, .channels_min = 2, .channels_max = 2, /* NID is set in stac92xx_build_pcms */};static struct hda_pcm_stream stac92xx_pcm_analog_playback = { .substreams = 1, .channels_min = 2, .channels_max = 8, .nid = 0x02, /* NID to query formats and rates */ .ops = { .open = stac92xx_playback_pcm_open, .prepare = stac92xx_playback_pcm_prepare, .cleanup = stac92xx_playback_pcm_cleanup },};static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, .nid = 0x06, /* NID to query formats and rates */ .ops = { .open = stac92xx_playback_pcm_open, .prepare = stac92xx_playback_pcm_prepare, .cleanup = stac92xx_playback_pcm_cleanup },};static struct hda_pcm_stream stac92xx_pcm_analog_capture = { .substreams = 2, .channels_min = 2, .channels_max = 2, /* NID is set in stac92xx_build_pcms */ .ops = { .prepare = stac92xx_capture_pcm_prepare, .cleanup = stac92xx_capture_pcm_cleanup },};static int stac92xx_build_pcms(struct hda_codec *codec){ struct sigmatel_spec *spec = codec->spec; struct hda_pcm *info = spec->pcm_rec; codec->num_pcms = 1; codec->pcm_info = info; info->name = "STAC92xx Analog"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; if (spec->alt_switch) { codec->num_pcms++; info++; info->name = "STAC92xx Analog Alt"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback; } if (spec->multiout.dig_out_nid || spec->dig_in_nid) { codec->num_pcms++; info++; info->name = "STAC92xx Digital"; if (spec->multiout.dig_out_nid) { info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; } if (spec->dig_in_nid) { info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } } return 0;}static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type){ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);}static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; int io_idx = kcontrol-> private_value & 0xff; ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; return 0;}static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; hda_nid_t nid = kcontrol->private_value >> 8; int io_idx = kcontrol-> private_value & 0xff; unsigned short val = ucontrol->value.integer.value[0]; spec->io_switch[io_idx] = val; if (val) stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); else stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_IN_EN); return 1;}#define STAC_CODEC_IO_SWITCH(xname, xpval) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = 0, \ .info = stac92xx_io_switch_info, \ .get = stac92xx_io_switch_get, \ .put = stac92xx_io_switch_put, \ .private_value = xpval, \ }enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_IO_SWITCH,};static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_CODEC_IO_SWITCH(NULL, 0),};/* add dynamic controls */static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val){ struct snd_kcontrol_new *knew; if (spec->num_kctl_used >= spec->num_kctl_alloc) { int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */ if (! knew) return -ENOMEM; if (spec->kctl_alloc) { memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc); kfree(spec->kctl_alloc); } spec->kctl_alloc = knew; spec->num_kctl_alloc = num; } knew = &spec->kctl_alloc[spec->num_kctl_used]; *knew = stac92xx_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; knew->private_value = val; spec->num_kctl_used++; return 0;}/* flag inputs as additional dynamic lineouts */static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; switch (cfg->line_outs) { case 3: /* add line-in as side */ if (cfg->input_pins[AUTO_PIN_LINE]) { cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } break; case 2: /* add line-in as clfe and mic as side */ if (cfg->input_pins[AUTO_PIN_LINE]) { cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC]) { cfg->line_out_pins[3] = cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } break; case 1: /* add line-in as surr and mic as clfe */ if (cfg->input_pins[AUTO_PIN_LINE]) { cfg->line_out_pins[1] = cfg->input_pins[AUTO_PIN_LINE]; spec->line_switch = 1; cfg->line_outs++; } if (cfg->input_pins[AUTO_PIN_MIC]) { cfg->line_out_pins[2] = cfg->input_pins[AUTO_PIN_MIC]; spec->mic_switch = 1; cfg->line_outs++; } break; } return 0;}/* * XXX The line_out pin widget connection list may not be set to the * desired DAC nid. This is the case on 927x where ports A and B can * be routed to several DACs. * * This requires an analysis of the line-out/hp pin configuration * to provide a best fit for pin/DAC configurations that are routable. * For now, 927x DAC4 is not supported and 927x DAC1 output to ports * A and B is not supported. *//* fill in the dac_nids table from the parsed pin configuration */static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg){ struct sigmatel_spec *spec = codec->spec; hda_nid_t nid; int i; /* check the pins hardwired to audio widget */ for (i = 0; i < cfg->line_outs; i++) { nid = cfg->line_out_pins[i]; spec->multiout.dac_nids[i] = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; } if (cfg->line_outs) spec->multiout.num_dacs = cfg->line_outs; else if (cfg->hp_pin) { spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; spec->multiout.num_dacs = 1; } return 0;}/* add playback controls from the parsed DAC table */static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg){ char name[32]; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid; int i, err; for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; nid = spec->multiout.dac_nids[i]; if (i == 2) { /* Center/LFE */ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) return err; if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume", HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) return err; if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0) return err; if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0) return err; } else { sprintf(name, "%s Playback Volume", chname[i]); if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) return err; sprintf(name, "%s Playback Switch", chname[i]); if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0) return err; } } if (spec->line_switch) if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0) return err; if (spec->mic_switch) if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0) return err; return 0;}/* add playback controls for HP output */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 pin = cfg->hp_pin; hda_nid_t nid; int i, err; unsigned int wid_caps; if (! pin) return 0; wid_caps = get_wcaps(codec, pin); if (wid_caps & AC_WCAP_UNSOL_CAP) /* Enable unsolicited responses on the HP widget */ snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_UNSOLICITED_ENABLE, STAC_UNSOL_ENABLE); nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; for (i = 0; i < cfg->line_outs; i++) { if (! spec->multiout.dac_nids[i]) continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -