📄 patch_analog.c
字号:
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, /* SPDIF route: PCM */ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Front Pin */ {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* HP Pin */ {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* Mono Pin */ {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, /* Front & Rear Mic Pins */ {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, /* Line Pin */ {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, /* Digital Beep */ {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Line-Out as Input: disabled */ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, { } /* end */};#ifdef CONFIG_SND_HDA_POWER_SAVEstatic struct hda_amp_list ad1981_loopbacks[] = { { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ { 0x13, HDA_OUTPUT, 0 }, /* Line */ { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ { 0x1d, HDA_OUTPUT, 0 }, /* CD */ { } /* end */};#endif/* * Patch for HP nx6320 * * nx6320 uses EAPD in the reverse way - EAPD-on means the internal * speaker output enabled _and_ mute-LED off. */#define AD1981_HP_EVENT 0x37#define AD1981_MIC_EVENT 0x38static struct hda_verb ad1981_hp_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, {}};/* turn on/off EAPD (+ mute HP) as a master switch */static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; if (! ad198x_eapd_put(kcontrol, ucontrol)) return 0; /* toggle HP mute appropriately */ snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, HDA_AMP_MUTE, spec->cur_eapd ? 0 : HDA_AMP_MUTE); return 1;}/* bind volumes of both NID 0x05 and 0x06 */static struct hda_bind_ctls ad1981_hp_bind_master_vol = { .ops = &snd_hda_bind_vol, .values = { HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), 0 },};/* mute internal speaker if HP is plugged */static void ad1981_hp_automute(struct hda_codec *codec){ unsigned int present; present = snd_hda_codec_read(codec, 0x06, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);}/* toggle input of built-in and mic jack appropriately */static void ad1981_hp_automic(struct hda_codec *codec){ static struct hda_verb mic_jack_on[] = { {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} }; static struct hda_verb mic_jack_off[] = { {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, {} }; unsigned int present; present = snd_hda_codec_read(codec, 0x08, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; if (present) snd_hda_sequence_write(codec, mic_jack_on); else snd_hda_sequence_write(codec, mic_jack_off);}/* unsolicited event for HP jack sensing */static void ad1981_hp_unsol_event(struct hda_codec *codec, unsigned int res){ res >>= 26; switch (res) { case AD1981_HP_EVENT: ad1981_hp_automute(codec); break; case AD1981_MIC_EVENT: ad1981_hp_automic(codec); break; }}static struct hda_input_mux ad1981_hp_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, { "Docking-Station", 0x1 }, { "Mix", 0x2 }, },};static struct snd_kcontrol_new ad1981_hp_mixers[] = { HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", .info = ad198x_eapd_info, .get = ad198x_eapd_get, .put = ad1981_hp_master_sw_put, .private_value = 0x05, }, HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),#if 0 /* FIXME: analog mic/line loopback doesn't work with my tests... * (although recording is OK) */ HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), /* FIXME: does this laptop have analog CD connection? */ HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),#endif HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = ad198x_mux_enum_info, .get = ad198x_mux_enum_get, .put = ad198x_mux_enum_put, }, { } /* end */};/* initialize jack-sensing, too */static int ad1981_hp_init(struct hda_codec *codec){ ad198x_init(codec); ad1981_hp_automute(codec); ad1981_hp_automic(codec); return 0;}/* configuration for Toshiba Laptops */static struct hda_verb ad1981_toshiba_init_verbs[] = { {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ /* pin sensing on HP and Mic jacks */ {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, {}};static struct snd_kcontrol_new ad1981_toshiba_mixers[] = { HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), { }};/* configuration for Lenovo Thinkpad T60 */static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = ad198x_mux_enum_info, .get = ad198x_mux_enum_get, .put = ad198x_mux_enum_put, }, /* identical with AD1983 */ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", .info = ad1983_spdif_route_info, .get = ad1983_spdif_route_get, .put = ad1983_spdif_route_put, }, { } /* end */};static struct hda_input_mux ad1981_thinkpad_capture_source = { .num_items = 3, .items = { { "Mic", 0x0 }, { "Mix", 0x2 }, { "CD", 0x4 }, },};/* models */enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD, AD1981_TOSHIBA, AD1981_MODELS};static const char *ad1981_models[AD1981_MODELS] = { [AD1981_HP] = "hp", [AD1981_THINKPAD] = "thinkpad", [AD1981_BASIC] = "basic", [AD1981_TOSHIBA] = "toshiba"};static struct snd_pci_quirk ad1981_cfg_tbl[] = { /* All HP models */ SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), /* HP nx6320 (reversed SSID, H/W bug) */ SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), /* Lenovo Thinkpad T60/X60/Z6xx */ SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), {}};static int patch_ad1981(struct hda_codec *codec){ struct ad198x_spec *spec; int board_config; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; codec->spec = spec; spec->multiout.max_channels = 2; spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); spec->multiout.dac_nids = ad1981_dac_nids; spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; spec->num_adc_nids = 1; spec->adc_nids = ad1981_adc_nids; spec->capsrc_nids = ad1981_capsrc_nids; spec->input_mux = &ad1981_capture_source; spec->num_mixers = 1; spec->mixers[0] = ad1981_mixers; spec->num_init_verbs = 1; spec->init_verbs[0] = ad1981_init_verbs; spec->spdif_route = 0;#ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = ad1981_loopbacks;#endif codec->patch_ops = ad198x_patch_ops; /* override some parameters */ board_config = snd_hda_check_board_config(codec, AD1981_MODELS, ad1981_models, ad1981_cfg_tbl); switch (board_config) { case AD1981_HP: spec->mixers[0] = ad1981_hp_mixers; spec->num_init_verbs = 2; spec->init_verbs[1] = ad1981_hp_init_verbs; spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1981_hp_capture_source; codec->patch_ops.init = ad1981_hp_init; codec->patch_ops.unsol_event = ad1981_hp_unsol_event; break; case AD1981_THINKPAD: spec->mixers[0] = ad1981_thinkpad_mixers; spec->input_mux = &ad1981_thinkpad_capture_source; break; case AD1981_TOSHIBA: spec->mixers[0] = ad1981_hp_mixers; spec->mixers[1] = ad1981_toshiba_mixers; spec->num_init_verbs = 2; spec->init_verbs[1] = ad1981_toshiba_init_verbs; spec->multiout.dig_out_nid = 0; spec->input_mux = &ad1981_hp_capture_source; codec->patch_ops.init = ad1981_hp_init; codec->patch_ops.unsol_event = ad1981_hp_unsol_event; break; } return 0;}/* * AD1988 * * Output pins and routes * * Pin Mix Sel DAC (*) * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a * port-D 0x12 (mute/hp) <- 0x29 <- 04 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a * port-F 0x16 (mute) <- 0x2a <- 06 * port-G 0x24 (mute) <- 0x27 <- 05 * port-H 0x25 (mute) <- 0x28 <- 0a * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06 * * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug. * * Input pins and routes * * pin boost mix input # / adc input # * port-A 0x11 -> 0x38 -> mix 2, ADC 0 * port-B 0x14 -> 0x39 -> mix 0, ADC 1 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2 * port-D 0x12 -> 0x3d -> mix 3, ADC 8 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4 * port-F 0x16 -> 0x3b -> mix 5, ADC 3 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7 * * * DAC assignment * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03 * * Inputs of Analog Mix (0x20) * 0:Port-B (front mic) * 1:Port-C/G/H (line-in) * 2:Port-A * 3:Port-D (line-in/2) * 4:Port-E/G/H (mic-in) * 5:Port-F (mic2-in) * 6:CD * 7:Beep * * ADC selection * 0:Port-A * 1:Port-B (front mic-in) * 2:Port-C (line-in) * 3:Port-F (mic2-in) * 4:Port-E (mic-in) * 5:CD * 6:Port-G * 7:Port-H * 8:Port-D (line-in/2) * 9:Mix * * Proposed pin assignments by the datasheet * * 6-stack * Port-A front headphone * B front mic-in * C rear line-in * D rear front-out * E rear mic-in * F rear surround * G rear CLFE * H rear side * * 3-stack * Port-A front headphone * B front mic * C rear line-in/surround * D rear front-out * E rear mic-in/CLFE * * laptop * Port-A headphone * B mic-in * C docking station * D internal speaker (with EAPD) * E/F quad mic array
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -