📄 ac97_codec.c
字号:
mute_mask = 0x8000; val = snd_ac97_read(ac97, reg); if (check_stereo || (ac97->flags & AC97_STEREO_MUTES)) { /* check whether both mute bits work */ val1 = val | 0x8080; snd_ac97_write(ac97, reg, val1); if (val1 == snd_ac97_read(ac97, reg)) mute_mask = 0x8080; } if (mute_mask == 0x8080) { struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 15, 7, 1, 1); if (check_amix) tmp.private_value |= (1 << 30); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } else { struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 15, 1, 1); if (check_amix) tmp.private_value |= (1 << 30); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } err = snd_ctl_add(card, kctl); if (err < 0) return err; /* mute as default */ snd_ac97_write_cache(ac97, reg, val | mute_mask); return 0;}/* * set dB information */static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0);static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0);static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);static const unsigned int *find_db_scale(unsigned int maxval){ switch (maxval) { case 0x0f: return db_scale_4bit; case 0x1f: return db_scale_5bit; case 0x3f: return db_scale_6bit; } return NULL;}static void set_tlv_db_scale(struct snd_kcontrol *kctl, const unsigned int *tlv){ kctl->tlv.p = tlv; if (tlv) kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;}/* * create a volume for normal stereo/mono controls */static int snd_ac97_cvol_new(struct snd_card *card, char *name, int reg, unsigned int lo_max, unsigned int hi_max, struct snd_ac97 *ac97){ int err; struct snd_kcontrol *kctl; if (! snd_ac97_valid_reg(ac97, reg)) return 0; if (hi_max) { /* invert */ struct snd_kcontrol_new tmp = AC97_DOUBLE(name, reg, 8, 0, lo_max, 1); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } else { /* invert */ struct snd_kcontrol_new tmp = AC97_SINGLE(name, reg, 0, lo_max, 1); tmp.index = ac97->num; kctl = snd_ctl_new1(&tmp, ac97); } if (reg >= AC97_PHONE && reg <= AC97_PCM) set_tlv_db_scale(kctl, db_scale_5bit_12db_max); else set_tlv_db_scale(kctl, find_db_scale(lo_max)); err = snd_ctl_add(card, kctl); if (err < 0) return err; snd_ac97_write_cache(ac97, reg, (snd_ac97_read(ac97, reg) & 0x8080) | lo_max | (hi_max << 8)); return 0;}/* * create a mute-switch and a volume for normal stereo/mono controls */static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, int reg, int check_stereo, int check_amix, struct snd_ac97 *ac97){ int err; char name[44]; unsigned char lo_max, hi_max; if (! snd_ac97_valid_reg(ac97, reg)) return 0; if (snd_ac97_try_bit(ac97, reg, 15)) { sprintf(name, "%s Switch", pfx); if ((err = snd_ac97_cmute_new_stereo(card, name, reg, check_stereo, check_amix, ac97)) < 0) return err; } check_volume_resolution(ac97, reg, &lo_max, &hi_max); if (lo_max) { sprintf(name, "%s Volume", pfx); if ((err = snd_ac97_cvol_new(card, name, reg, lo_max, hi_max, ac97)) < 0) return err; } return 0;}#define snd_ac97_cmix_new(card, pfx, reg, acheck, ac97) \ snd_ac97_cmix_new_stereo(card, pfx, reg, 0, acheck, ac97)#define snd_ac97_cmute_new(card, name, reg, acheck, ac97) \ snd_ac97_cmute_new_stereo(card, name, reg, 0, acheck, ac97)static unsigned int snd_ac97_determine_spdif_rates(struct snd_ac97 *ac97);static int snd_ac97_mixer_build(struct snd_ac97 * ac97){ struct snd_card *card = ac97->bus->card; struct snd_kcontrol *kctl; int err; unsigned int idx; unsigned char max; /* build master controls */ /* AD claims to remove this control from AD1887, although spec v2.2 does not allow this */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { if (ac97->flags & AC97_HAS_NO_MASTER_VOL) err = snd_ac97_cmute_new(card, "Master Playback Switch", AC97_MASTER, 0, ac97); else err = snd_ac97_cmix_new(card, "Master Playback", AC97_MASTER, 0, ac97); if (err < 0) return err; } ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080; /* build center controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) && !(ac97->flags & AC97_AD_MULTI)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0) return err; snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 0, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; set_tlv_db_scale(kctl, find_db_scale(max)); snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max); } /* build LFE controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) && !(ac97->flags & AC97_AD_MULTI)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0) return err; snd_ac97_change_volume_params2(ac97, AC97_CENTER_LFE_MASTER, 8, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; set_tlv_db_scale(kctl, find_db_scale(max)); snd_ac97_write_cache(ac97, AC97_CENTER_LFE_MASTER, ac97->regs[AC97_CENTER_LFE_MASTER] | max << 8); } /* build surround controls */ if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) && !(ac97->flags & AC97_AD_MULTI)) { /* Surround Master (0x38) is with stereo mutes */ if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, 0, ac97)) < 0) return err; } /* build headphone controls */ if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, 0, ac97)) < 0) return err; } /* build master mono controls */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { if ((err = snd_ac97_cmix_new(card, "Master Mono Playback", AC97_MASTER_MONO, 0, ac97)) < 0) return err; } /* build master tone controls */ if (!(ac97->flags & AC97_HAS_NO_TONE)) { if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) { for (idx = 0; idx < 2; idx++) { if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0) return err; if (ac97->id == AC97_ID_YMF743 || ac97->id == AC97_ID_YMF753) { kctl->private_value &= ~(0xff << 16); kctl->private_value |= 7 << 16; } } snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f); } } /* build PC Speaker controls */ if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && ((ac97->flags & AC97_HAS_PC_BEEP) || snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_4bit); snd_ac97_write_cache(ac97, AC97_PC_BEEP, snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e); } /* build Phone controls */ if (!(ac97->flags & AC97_HAS_NO_PHONE)) { if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { if ((err = snd_ac97_cmix_new(card, "Phone Playback", AC97_PHONE, 1, ac97)) < 0) return err; } } /* build MIC controls */ if (!(ac97->flags & AC97_HAS_NO_MIC)) { if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) { if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, 1, ac97)) < 0) return err; if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0) return err; } } /* build Line controls */ if (snd_ac97_try_volume_mix(ac97, AC97_LINE)) { if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 1, ac97)) < 0) return err; } /* build CD controls */ if (!(ac97->flags & AC97_HAS_NO_CD)) { if (snd_ac97_try_volume_mix(ac97, AC97_CD)) { if ((err = snd_ac97_cmix_new(card, "CD Playback", AC97_CD, 1, ac97)) < 0) return err; } } /* build Video controls */ if (!(ac97->flags & AC97_HAS_NO_VIDEO)) { if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { if ((err = snd_ac97_cmix_new(card, "Video Playback", AC97_VIDEO, 1, ac97)) < 0) return err; } } /* build Aux controls */ if (!(ac97->flags & AC97_HAS_NO_AUX)) { if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, 1, ac97)) < 0) return err; } } /* build PCM controls */ if (ac97->flags & AC97_AD_MULTI) { unsigned short init_val; if (ac97->flags & AC97_STEREO_MUTES) init_val = 0x9f9f; else init_val = 0x9f1f; for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[0] = init_val; if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[1] = init_val; } if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_5bit); for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_5bit); ac97->spec.ad18xx.pcmreg[2] = init_val; } snd_ac97_write_cache(ac97, AC97_PCM, init_val); } else { if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) { if (ac97->flags & AC97_HAS_NO_PCM_VOL) err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, 0, ac97); else err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, 0, ac97); if (err < 0) return err; } } /* build Capture controls */ if (!(ac97->flags & AC97_HAS_NO_REC_GAIN)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_control_capture_src, ac97))) < 0) return err; if (snd_ac97_try_bit(ac97, AC97_REC_GAIN, 15)) { err = snd_ac97_cmute_new(card, "Capture Switch", AC97_REC_GAIN, 0, ac97); if (err < 0) return err; } if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_control_capture_vol, ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_rec_gain); snd_ac97_write_cache(ac97, AC97_REC_SEL, 0x0000); snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x0000); } /* build MIC Capture controls */ if (snd_ac97_try_volume_mix(ac97, AC97_REC_GAIN_MIC)) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic_capture[idx], ac97))) < 0) return err; set_tlv_db_scale(kctl, db_scale_rec_gain); snd_ac97_write_cache(ac97, AC97_REC_GAIN_MIC, 0x0000); } /* build PCM out path & mute control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 15)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_PCM_OUT], ac97))) < 0) return err; } /* build Simulated Stereo Enhancement control */ if (ac97->caps & 0x0008) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_STEREO_ENHANCEMENT], ac97))) < 0) return err; } /* build 3D Stereo Enhancement control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 13)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_3D], ac97))) < 0) return err; } /* build Loudness control */ if (ac97->caps & 0x0020) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_LOUDNESS], ac97))) < 0) return err; } /* build Mono output select control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 9)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MONO], ac97))) < 0) return err; } /* build Mic select control */ if (snd_ac97_try_bit(ac97, AC97_GENERAL_PURPOSE, 8)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_general[AC97_GENERAL_MIC], ac97))) < 0) return err; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -