📄 ac97_codec.c
字号:
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA",AC97_EXTENDED_STATUS, 4, 3, 0)};#define AD18XX_PCM_BITS(xname, codec, shift, mask) \{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, info: snd_ac97_ad18xx_pcm_info_bits, \ get: snd_ac97_ad18xx_pcm_get_bits, put: snd_ac97_ad18xx_pcm_put_bits, \ private_value: codec | (shift << 8) | (mask << 16) }static int snd_ac97_ad18xx_pcm_info_bits(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 16) & 0xff; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_ac97_ad18xx_pcm_get_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; ucontrol->value.integer.value[0] = mask - ((ac97->spec.ad18xx.pcmreg[codec] >> shift) & mask); return 0;}static int snd_ac97_ad18xx_pcm_put_bits(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; unsigned short val; val = mask - (ucontrol->value.integer.value[0] & mask); return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, mask << shift, val << shift);}#define AD18XX_PCM_VOLUME(xname, codec) \{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, info: snd_ac97_ad18xx_pcm_info_volume, \ get: snd_ac97_ad18xx_pcm_get_volume, put: snd_ac97_ad18xx_pcm_put_volume, \ private_value: codec }static int snd_ac97_ad18xx_pcm_info_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 31; return 0;}static int snd_ac97_ad18xx_pcm_get_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; spin_lock(&ac97->reg_lock); ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31); ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31); spin_unlock(&ac97->reg_lock); return 0;}static int snd_ac97_ad18xx_pcm_put_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int codec = kcontrol->private_value & 3; unsigned short val1, val2; val1 = 31 - (ucontrol->value.integer.value[0] & 31); val2 = 31 - (ucontrol->value.integer.value[1] & 31); return snd_ac97_ad18xx_update_pcm_bits(ac97, codec, 0x1f1f, (val1 << 8) | val2);}static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_pcm[2] = {AD18XX_PCM_BITS("PCM Playback Switch", 0, 15, 1),AD18XX_PCM_VOLUME("PCM Playback Volume", 0)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_surround[2] = {AD18XX_PCM_BITS("Surround Playback Switch", 1, 15, 1),AD18XX_PCM_VOLUME("Surround Playback Volume", 1)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_center[2] = {AD18XX_PCM_BITS("Center Playback Switch", 2, 15, 1),AD18XX_PCM_BITS("Center Playback Volume", 2, 8, 31)};static const snd_kcontrol_new_t snd_ac97_controls_ad18xx_lfe[1] = {AD18XX_PCM_BITS("LFE Playback Volume", 2, 0, 31)};/* * */static int snd_ac97_free(ac97_t *ac97){ if (ac97) { snd_ac97_proc_done(ac97); if (ac97->private_free) ac97->private_free(ac97); snd_magic_kfree(ac97); } return 0;}static int snd_ac97_dev_free(snd_device_t *device){ ac97_t *ac97 = snd_magic_cast(ac97_t, device->device_data, return -ENXIO); return snd_ac97_free(ac97);}static int snd_ac97_try_volume_mix(ac97_t * ac97, int reg){ unsigned short val, mask = 0x8000; switch (reg) { case AC97_MASTER_TONE: return ac97->caps & 0x04 ? 1 : 0; case AC97_HEADPHONE: return ac97->caps & 0x10 ? 1 : 0; case AC97_REC_GAIN_MIC: return ac97->caps & 0x01 ? 1 : 0; case AC97_3D_CONTROL: if (ac97->caps & 0x7c00) { val = snd_ac97_read(ac97, reg); /* if nonzero - fixed and we can't set it */ return val == 0; } return 0; case AC97_CENTER_LFE_MASTER: /* center */ if ((ac97->ext_id & 0x40) == 0) return 0; break; case AC97_CENTER_LFE_MASTER+1: /* lfe */ if ((ac97->ext_id & 0x100) == 0) return 0; reg = AC97_CENTER_LFE_MASTER; mask = 0x0080; break; case AC97_SURROUND_MASTER: if ((ac97->ext_id & 0x80) == 0) return 0; break; } val = snd_ac97_read(ac97, reg); if (!(val & mask)) { /* nothing seems to be here - mute flag is not set */ /* try another test */ snd_ac97_write_cache_test(ac97, reg, val | mask); val = snd_ac97_read(ac97, reg); if (!(val & mask)) return 0; /* nothing here */ } return 1; /* success, useable */}static int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit){ unsigned short mask, val, orig, res; mask = 1 << bit; orig = snd_ac97_read(ac97, reg); val = orig ^ mask; snd_ac97_write(ac97, reg, val); res = snd_ac97_read(ac97, reg); snd_ac97_write_cache(ac97, reg, orig); return res == val;}static void snd_ac97_change_volume_params1(ac97_t * ac97, int reg, unsigned char *max){ unsigned short val, val1; *max = 63; val = 0x8000 | 0x0020; snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 31; } /* reset volume to zero */ snd_ac97_write_cache(ac97, reg, 0x8000);}static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max){ unsigned short val, val1; *max = 63; val = 0x8080 | (0x20 << shift); snd_ac97_write(ac97, reg, val); val1 = snd_ac97_read(ac97, reg); if (val != val1) { *max = 31; } /* reset volume to zero */ snd_ac97_write_cache(ac97, reg, 0x8080);}static inline int printable(unsigned int x){ x &= 0xff; if (x < ' ' || x >= 0x71) { if (x <= 0x89) return x - 0x71 + 'A'; return '?'; } return x;}static snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97){ snd_kcontrol_new_t template; memcpy(&template, _template, sizeof(template)); snd_runtime_check(!template.index, return NULL); template.index = ac97->num; return snd_ctl_new1(&template, ac97);}static int snd_ac97_mixer_build(snd_card_t * card, ac97_t * ac97){ snd_kcontrol_t *kctl; int err, idx; unsigned char max; /* build master controls */ /* AD claims to remove this control from AD1887, although spec v2.2 don't allow this */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master[1], ac97))) < 0) return err; snd_ac97_change_volume_params1(ac97, AC97_MASTER, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; snd_ac97_write_cache(ac97, AC97_MASTER, 0x8000 | max | (max << 8)); } ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080; /* build center controls */ if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) { 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; 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)) { 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; 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)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_surround[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_surround[1], ac97))) < 0) return err; snd_ac97_change_volume_params2(ac97, AC97_SURROUND_MASTER, 0, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x8080 | max | (max << 8)); } /* build headphone controls */ if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_headphone[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_headphone[1], ac97))) < 0) return err; snd_ac97_change_volume_params1(ac97, AC97_HEADPHONE, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; snd_ac97_write_cache(ac97, AC97_HEADPHONE, 0x8000 | max | (max << 8)); } /* build master mono controls */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_MONO)) { if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_master_mono[0], ac97))) < 0) return err; if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_master_mono[1], ac97))) < 0) return err; snd_ac97_change_volume_params1(ac97, AC97_MASTER_MONO, &max); kctl->private_value &= ~(0xff << 16); kctl->private_value |= (int)max << 16; snd_ac97_write_cache(ac97, AC97_MASTER_MONO, 0x8000 | max); } /* build master tone controls */ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f); } /* build PC Speaker controls */ if ((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, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); } /* build Phone controls */ if (snd_ac97_try_volume_mix(ac97, AC97_PHONE)) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_phone[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_PHONE, 0x801f); } /* build MIC controls */ for (idx = 0; idx < 3; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_MIC, 0x801f); /* build Line controls */ for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_line[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_LINE, 0x9f1f); /* build CD controls */ for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_cd[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_CD, 0x9f1f); /* build Video controls */ if (snd_ac97_try_volume_mix(ac97, AC97_VIDEO)) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_video[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_VIDEO, 0x9f1f); } /* build Aux controls */ if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_aux[idx], ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_AUX, 0x9f1f); } /* build PCM controls */ if (ac97->flags & AC97_AD_MULTI) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_pcm[idx], ac97))) < 0) return err; ac97->spec.ad18xx.pcmreg[0] = 0x9f1f; if (ac97->scaps & AC97_SCAP_SURROUND_DAC) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_surround[idx], ac97))) < 0) return err; ac97->spec.ad18xx.pcmreg[1] = 0x9f1f; } if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) { for (idx = 0; idx < 2; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_center[idx], ac97))) < 0) return err; if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_ad18xx_lfe[0], ac97))) < 0) return err; ac97->spec.ad18xx.pcmreg[2] = 0x9f1f; } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -