ac97_patch.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,858 行 · 第 1/4 页
C
1,858 行
return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, ucontrol->value.integer.value[0] ? (1 << 10) : 0, 0);}static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 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 ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12, (unsigned short)ucontrol->value.enumerated.item[0], 0);}static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = { AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0), AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 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; /* assume only page 0 for writing cache */ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); /* 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;}#define AC97_ALC850_JACK_SELECT 0x76#define AC97_ALC850_MISC1 0x7astatic int ac97_alc850_surround_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_ALC850_JACK_SELECT] >> 12) & 7) == 2; return 0;}static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); /* SURR 1kOhm (bit4), Amp (bit5) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); /* LINE-IN = 0, SURROUND = 2 */ return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, ucontrol->value.integer.value[0] ? (2<<12) : (0<<12));}static int ac97_alc850_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_ALC850_JACK_SELECT] >> 4) & 7) == 2; return 0;}static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol){ ac97_t *ac97 = snd_kcontrol_chip(kcontrol); /* Vref disable (bit12), 1kOhm (bit13) */ snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); /* MIC-IN = 1, CENTER-LFE = 2 */ return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, ucontrol->value.integer.value[0] ? (2<<4) : (1<<4));}static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line-In As Surround", .info = snd_ac97_info_single, .get = ac97_alc850_surround_get, .put = ac97_alc850_surround_put, .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Mic As Center/LFE", .info = snd_ac97_info_single, .get = ac97_alc850_mic_get, .put = ac97_alc850_mic_put, .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ },};static int patch_alc850_specific(ac97_t *ac97){ int err; if ((err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850))) < 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_alc850_ops = { .build_specific = patch_alc850_specific};int patch_alc850(ac97_t *ac97){ ac97->build_ops = &patch_alc850_ops; ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */ /* assume only page 0 for writing cache */ snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR); /* adjust default values */ /* 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); /* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off * Front Amp: on, Vref: enable, Center 1kOhm: on, Mix: on */ snd_ac97_write_cache(ac97, 0x7a, (1<<1)|(1<<4)|(0<<5)|(1<<6)| (1<<7)|(0<<12)|(1<<13)|(0<<14)); /* detection UIO2,3: all path floating, UIO3: MIC, Vref2: disable, * UIO1: FRONT, Vref3: disable, UIO3: LINE, Front-Mic: mute */ snd_ac97_write_cache(ac97, 0x76, (0<<0)|(0<<2)|(1<<4)|(1<<7)|(2<<8)| (1<<11)|(0<<12)|(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); ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */ } else { ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */ ac97->rates[AC97_RATES_SPDIF] = 0; } /* 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 + -
显示快捷键?