ac97_patch.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,701 行 · 第 1/4 页
C
1,701 行
num++; if (num == 1) { /* ok, deselect all ID bits */ snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000); ac97->spec.ad18xx.codec_cfg[0] = ac97->spec.ad18xx.codec_cfg[1] = ac97->spec.ad18xx.codec_cfg[2] = 0x0000; } /* required for AD1886/AD1885 combination */ ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID); if (ac97->spec.ad18xx.id[0]) { ac97->id &= 0xffff0000; ac97->id |= ac97->spec.ad18xx.id[0]; } return 0;}static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = { AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0), /* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */ AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0), AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0),};static int patch_ad1885_specific(ac97_t * ac97){ int err; if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) return err; return 0;}static struct snd_ac97_build_ops patch_ad1885_build_ops = { .build_specific = &patch_ad1885_specific};int patch_ad1885(ac97_t * ac97){ unsigned short jack; patch_ad1881(ac97); /* This is required to deal with the Intel D815EEAL2 */ /* i.e. Line out is actually headphone out from codec */ /* turn off jack sense bits D8 & D9 */ jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF); snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300); /* set default */ snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404); ac97->build_ops = &patch_ad1885_build_ops; return 0;}int patch_ad1886(ac97_t * ac97){ patch_ad1881(ac97); /* Presario700 workaround */ /* for Jack Sense/SPDIF Register misetting causing */ snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010); return 0;}/* MISC bits */#define AC97_AD198X_MBC 0x0003 /* mic boost */#define AC97_AD198X_MBC_20 0x0000 /* +20dB */#define AC97_AD198X_MBC_10 0x0001 /* +10dB */#define AC97_AD198X_MBC_30 0x0002 /* +30dB */#define AC97_AD198X_VREFD 0x0004 /* VREF high-Z */#define AC97_AD198X_VREFH 0x0008 /* 2.25V, 3.7V */#define AC97_AD198X_VREF_0 0x000c /* 0V */#define AC97_AD198X_SRU 0x0010 /* sample rate unlock */#define AC97_AD198X_LOSEL 0x0020 /* LINE_OUT amplifiers input select */#define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */#define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */#define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */#define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */#define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */#define AC97_AD198X_LODIS 0x1000 /* LINE_OUT disable */#define AC97_AD198X_MSPLT 0x2000 /* mute split */#define AC97_AD198X_AC97NC 0x4000 /* AC97 no compatible mode */#define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */static int snd_ac97_ad198x_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ static char *texts[2] = { "AC-Link", "A/D Converter" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 2; if (uinfo->value.enumerated.item > 1) uinfo->value.enumerated.item = 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_ac97_ad198x_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; val = ac97->regs[AC97_AD_SERIAL_CFG]; ucontrol->value.enumerated.item[0] = (val >> 2) & 1; return 0;}static int snd_ac97_ad198x_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; if (ucontrol->value.enumerated.item[0] > 1) return -EINVAL; val = ucontrol->value.enumerated.item[0] << 2; return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val);}static const snd_kcontrol_new_t snd_ac97_ad198x_spdif_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", .info = snd_ac97_ad198x_spdif_source_info, .get = snd_ac97_ad198x_spdif_source_get, .put = snd_ac97_ad198x_spdif_source_put,};static int patch_ad198x_post_spdif(ac97_t * ac97){ return patch_build_controls(ac97, &snd_ac97_ad198x_spdif_source, 1);}static struct snd_ac97_build_ops patch_ad1981a_build_ops = { .build_post_spdif = patch_ad198x_post_spdif};int patch_ad1981a(ac97_t *ac97){ patch_ad1881(ac97); ac97->build_ops = &patch_ad1981a_build_ops; snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); ac97->flags |= AC97_STEREO_MUTES; return 0;}static const snd_kcontrol_new_t snd_ac97_ad198x_2cmic =AC97_SINGLE("Stereo Mic", AC97_AD_MISC, 6, 1, 0);static int patch_ad1981b_specific(ac97_t *ac97){ return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);}static struct snd_ac97_build_ops patch_ad1981b_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1981b_specific};int patch_ad1981b(ac97_t *ac97){ patch_ad1881(ac97); ac97->build_ops = &patch_ad1981b_build_ops; snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); ac97->flags |= AC97_STEREO_MUTES; return 0;}static int snd_ac97_ad1888_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *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 snd_ac97_ad1888_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; val = ac97->regs[AC97_AD_MISC]; ucontrol->value.integer.value[0] = !(val & AC97_AD198X_LOSEL); return 0;}static int snd_ac97_ad1888_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; val = !ucontrol->value.integer.value[0] ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0; return snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val);}static int snd_ac97_ad1888_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 3; if (uinfo->value.enumerated.item > 2) uinfo->value.enumerated.item = 2; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_ac97_ad1888_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; val = ac97->regs[AC97_AD_MISC]; if (!(val & AC97_AD198X_DMIX1)) ucontrol->value.enumerated.item[0] = 0; else ucontrol->value.enumerated.item[0] = 1 + ((val >> 8) & 1); return 0;}static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; if (ucontrol->value.enumerated.item[0] > 2) return -EINVAL; if (ucontrol->value.enumerated.item[0] == 0) val = 0; else val = AC97_AD198X_DMIX1 | ((ucontrol->value.enumerated.item[0] - 1) << 8); return snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val);}static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Exchange Front/Surround", .info = snd_ac97_ad1888_lohpsel_info, .get = snd_ac97_ad1888_lohpsel_get, .put = snd_ac97_ad1888_lohpsel_put }, AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Downmix", .info = snd_ac97_ad1888_downmix_info, .get = snd_ac97_ad1888_downmix_get, .put = snd_ac97_ad1888_downmix_put }, AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0),};static int patch_ad1888_specific(ac97_t *ac97){ /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch"); snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume"); snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));}static struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1888_specific};int patch_ad1888(ac97_t * ac97){ unsigned short misc; patch_ad1881(ac97); ac97->build_ops = &patch_ad1888_build_ops; /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ /* AD-compatible mode */ /* Stereo mutes enabled */ misc = snd_ac97_read(ac97, AC97_AD_MISC); snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | AC97_AD198X_MSPLT | AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; return 0;}static int patch_ad1980_specific(ac97_t *ac97){ int err; if ((err = patch_ad1888_specific(ac97)) < 0) return err; return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1);}static struct snd_ac97_build_ops patch_ad1980_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1980_specific};int patch_ad1980(ac97_t * ac97){ patch_ad1888(ac97); ac97->build_ops = &patch_ad1980_build_ops; return 0;}static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0)};static int patch_ad1985_specific(ac97_t *ac97){ int err; if ((err = patch_ad1980_specific(ac97)) < 0) return err; return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls));}static struct snd_ac97_build_ops patch_ad1985_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1985_specific};int patch_ad1985(ac97_t * ac97){ unsigned short misc; patch_ad1881(ac97); ac97->build_ops = &patch_ad1985_build_ops; misc = snd_ac97_read(ac97, AC97_AD_MISC); /* switch front/surround line-out/hp-out */ /* center/LFE, mic in 3.75V mode */ /* AD-compatible mode */ /* Stereo mutes enabled */ /* in accordance with ADI driver: misc | 0x5c28 */ snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | AC97_AD198X_VREFH | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | AC97_AD198X_CLDIS | AC97_AD198X_LODIS | AC97_AD198X_MSPLT | AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; /* on AD1985 rev. 3, AC'97 revision bits are zero */ ac97->ext_id = (ac97->ext_id & ~AC97_EI_REV_MASK) | AC97_EI_REV_23; return 0;}/* * realtek ALC65x codecs */static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; return 0;}static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int change, val; val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); change = (ucontrol->value.integer.value[0] != val); if (change) { /* disable/enable vref */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, ucontrol->value.integer.value[0] ? (1 << 12) : 0); /* turn on/off center-on-mic */ snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, ucontrol->value.integer.value[0] ? (1 << 10) : 0); /* GPIO0 high for mic */ snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, ucontrol->value.integer.value[0] ? 0 : 0x100); } return change;}static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), /* 4: Analog Input To Surround */ /* 5: Analog Input To Center/LFE */ /* 6: Independent Master Volume Right */ /* 7: Independent Master Volume Left */ /* 8: reserved */ AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), /* 10: mic, see below */ /* 11-13: in IEC958 controls */ AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0),#if 0 /* always set in patch_alc650 */ AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1), AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1), AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1),#endif { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic As Center/LFE", .info = snd_ac97_info_single, .get = snd_ac97_alc650_mic_get, .put = snd_ac97_alc650_mic_put, .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ },};static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?