ac97_patch.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,701 行 · 第 1/4 页
C
1,701 行
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),};static int patch_alc650_specific(ac97_t * ac97){ int err; if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0) return err; if (ac97->ext_id & AC97_EI_SPDIF) { if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) return err; } return 0;}static struct snd_ac97_build_ops patch_alc650_ops = { .build_specific = patch_alc650_specific};int patch_alc650(ac97_t * ac97){ unsigned short val; ac97->build_ops = &patch_alc650_ops; /* revision E or F */ /* FIXME: what about revision D ? */ ac97->spec.dev_flags = (ac97->id == 0x414c4722 || ac97->id == 0x414c4723); /* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */ snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); /* Enable SPDIF-IN only on Rev.E and above */ val = snd_ac97_read(ac97, AC97_ALC650_CLOCK); /* SPDIF IN with pin 47 */ if (ac97->spec.dev_flags) val |= 0x03; /* enable */ else val &= ~0x03; /* disable */ snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, val); /* set default: slot 3,4,7,8,6,9 spdif-in monitor off, analog-spdif off, spdif-in off center on mic off, surround on line-in off downmix off, duplicate front off */ snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 0); /* set GPIO0 for mic bias */ /* GPIO0 pin output, no interrupt, high */ snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP) | 0x01); snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, (snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x100) & ~0x10); /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); return 0;}static int snd_ac97_alc655_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_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); int change; /* misc control; vrefout disable */ snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, ucontrol->value.integer.value[0] ? (1 << 12) : 0); change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, ucontrol->value.integer.value[0] ? (1 << 10) : 0); return change;}static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic As Center/LFE", .info = snd_ac97_info_single, .get = snd_ac97_alc655_mic_get, .put = snd_ac97_alc655_mic_put, .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ },};static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" }; static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" }; ac97_t *ac97 = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, ac97->spec.dev_flags ? texts_658[uinfo->value.enumerated.item] : texts_655[uinfo->value.enumerated.item]); return 0;}static int alc655_iec958_route_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_ALC650_MULTICH]; val = (val >> 12) & 3; if (ac97->spec.dev_flags && val == 3) val = 0; ucontrol->value.enumerated.item[0] = val; return 0;}static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12, (unsigned short)ucontrol->value.enumerated.item[0]);}static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = { AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "IEC958 Playback Route", .info = alc655_iec958_route_info, .get = alc655_iec958_route_get, .put = alc655_iec958_route_put, },};static int patch_alc655_specific(ac97_t * ac97){ int err; if ((err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655))) < 0) return err; if (ac97->ext_id & AC97_EI_SPDIF) { if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) return err; } return 0;}static struct snd_ac97_build_ops patch_alc655_ops = { .build_specific = patch_alc655_specific};int patch_alc655(ac97_t * ac97){ unsigned int val; ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */ ac97->build_ops = &patch_alc655_ops; /* adjust default values */ val = snd_ac97_read(ac97, 0x7a); /* misc control */ val |= (1 << 1); /* spdif input pin */ val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); /* set default: spdif-in enabled, spdif-in monitor off, spdif-in PCM off center on mic off, surround on line-in off duplicate front off */ snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15); /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); return 0;}/* * C-Media CM97xx codecs */static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0),};static int patch_cm9738_specific(ac97_t * ac97){ return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls));}static struct snd_ac97_build_ops patch_cm9738_ops = { .build_specific = patch_cm9738_specific};int patch_cm9738(ac97_t * ac97){ ac97->build_ops = &patch_cm9738_ops; return 0;}static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ static char *texts[] = { "Analog", "Digital" }; 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_cmedia_spdif_playback_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_CM9739_SPDIF_CTRL]; ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01; return 0;}static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL, 0x01 << 1, (ucontrol->value.enumerated.item[0] & 0x01) << 1);}static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { /* BIT 0: SPDI_EN - always true */ { /* BIT 1: SPDIFS */ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", .info = snd_ac97_cmedia_spdif_playback_source_info, .get = snd_ac97_cmedia_spdif_playback_source_get, .put = snd_ac97_cmedia_spdif_playback_source_put, }, /* BIT 2: IG_SPIV */ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0), /* BIT 3: SPI2F */ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), /* BIT 4: SPI2SDI */ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0), /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */};static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; return 0;}static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, ucontrol->value.integer.value[0] ? 0x1000 : 0x2000);}static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic As Center/LFE", .info = snd_ac97_info_single, .get = snd_ac97_cm9739_center_mic_get, .put = snd_ac97_cm9739_center_mic_put, .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ },};static int patch_cm9739_specific(ac97_t * ac97){ return patch_build_controls(ac97, snd_ac97_cm9739_controls, ARRAY_SIZE(snd_ac97_cm9739_controls));}static int patch_cm9739_post_spdif(ac97_t * ac97){ return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif));}static struct snd_ac97_build_ops patch_cm9739_ops = { .build_specific = patch_cm9739_specific, .build_post_spdif = patch_cm9739_post_spdif};int patch_cm9739(ac97_t * ac97){ unsigned short val; ac97->build_ops = &patch_cm9739_ops; /* check spdif */ val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); if (val & AC97_EA_SPCV) { /* enable spdif in */ snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL, snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) | 0x01); } else { ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */ } /* set-up multi channel */ /* bit 14: 0 = SPDIF, 1 = EAPD */ /* bit 13: enable internal vref output for mic */ /* bit 12: disable center/lfe (swithable) */ /* bit 10: disable surround/line (switchable) */ /* bit 9: mix 2 surround off */ /* bit 0: dB */ val = (1 << 13); if (! (ac97->ext_id & AC97_EI_SPDIF)) val |= (1 << 14); snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, val); /* FIXME: set up GPIO */ snd_ac97_write_cache(ac97, 0x70, 0x0100); snd_ac97_write_cache(ac97, 0x72, 0x0020); return 0;}/* * VIA VT1616 codec */static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = {AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0),AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),};static int patch_vt1616_specific(ac97_t * ac97){ int err; if (snd_ac97_try_bit(ac97, 0x5a, 9)) if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0) return err; if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) return err; return 0;}static struct snd_ac97_build_ops patch_vt1616_ops = { .build_specific = patch_vt1616_specific};int patch_vt1616(ac97_t * ac97){ ac97->build_ops = &patch_vt1616_ops; return 0;}static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0),};static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0), AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0), AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),};static int patch_it2646_specific(ac97_t * ac97){ int err; if ((err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646))) < 0) return err; if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646))) < 0) return err; return 0;}static struct snd_ac97_build_ops patch_it2646_ops = { .build_specific = patch_it2646_specific};int patch_it2646(ac97_t * ac97){ ac97->build_ops = &patch_it2646_ops; /* full DAC volume */ snd_ac97_write_cache(ac97, 0x5E, 0x0808); snd_ac97_write_cache(ac97, 0x7A, 0x0808); return 0;}/* Si3036/8 specific registers */#define AC97_SI3036_CHIP_ID 0x5aint mpatch_si3036(ac97_t * ac97){ //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); snd_ac97_write_cache(ac97, 0x68, 0); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?