diff options
Diffstat (limited to 'sound/pci/ac97/ac97_patch.c')
| -rw-r--r-- | sound/pci/ac97/ac97_patch.c | 398 |
1 files changed, 335 insertions, 63 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index f4fbc795ee8..99176221541 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -27,6 +27,15 @@ #include "ac97_patch.h" /* + * Forward declarations + */ + +static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97, + const char *name); +static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, + const unsigned int *tlv, const char **slaves); + +/* * Chip specific initialization */ @@ -371,7 +380,7 @@ static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97) return 0; } -static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { +static const struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { .build_spdif = patch_yamaha_ymf743_build_spdif, .build_3d = patch_yamaha_ymf7x3_3d, }; @@ -455,7 +464,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { +static const struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { .build_3d = patch_yamaha_ymf7x3_3d, .build_post_spdif = patch_yamaha_ymf753_post_spdif }; @@ -476,7 +485,7 @@ static int patch_yamaha_ymf753(struct snd_ac97 * ac97) } /* - * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com> + * May 2, 2003 Liam Girdwood <lrg@slimlogic.co.uk> * removed broken wolfson00 patch. * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. */ @@ -502,7 +511,7 @@ static int patch_wolfson_wm9703_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = { +static const struct snd_ac97_build_ops patch_wolfson_wm9703_ops = { .build_specific = patch_wolfson_wm9703_specific, }; @@ -533,7 +542,7 @@ static int patch_wolfson_wm9704_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = { +static const struct snd_ac97_build_ops patch_wolfson_wm9704_ops = { .build_specific = patch_wolfson_wm9704_specific, }; @@ -544,25 +553,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97) return 0; } -static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) -{ - int err, i; - for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { - if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) - return err; - } - snd_ac97_write_cache(ac97, 0x72, 0x0808); - return 0; -} - -static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { - .build_specific = patch_wolfson_wm9705_specific, -}; - static int patch_wolfson05(struct snd_ac97 * ac97) { /* WM9705, WM9710 */ - ac97->build_ops = &patch_wolfson_wm9705_ops; + ac97->build_ops = &patch_wolfson_wm9703_ops; #ifdef CONFIG_TOUCHSCREEN_WM9705 /* WM9705 touchscreen uses AUX and VIDEO for touch */ ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; @@ -692,7 +686,7 @@ static int patch_wolfson_wm9711_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = { +static const struct snd_ac97_build_ops patch_wolfson_wm9711_ops = { .build_specific = patch_wolfson_wm9711_specific, }; @@ -800,12 +794,12 @@ AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1), AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0), AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1), -AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1), -AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1), -AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1), -AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1), -AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1), -AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1), +AC97_SINGLE("Beep to Headphone Switch", AC97_AUX, 15, 1, 1), +AC97_SINGLE("Beep to Headphone Volume", AC97_AUX, 12, 7, 1), +AC97_SINGLE("Beep to Master Switch", AC97_AUX, 11, 1, 1), +AC97_SINGLE("Beep to Master Volume", AC97_AUX, 8, 7, 1), +AC97_SINGLE("Beep to Mono Switch", AC97_AUX, 7, 1, 1), +AC97_SINGLE("Beep to Mono Volume", AC97_AUX, 4, 7, 1), AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1), AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1), @@ -886,7 +880,7 @@ static void patch_wolfson_wm9713_resume (struct snd_ac97 * ac97) } #endif -static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = { +static const struct snd_ac97_build_ops patch_wolfson_wm9713_ops = { .build_specific = patch_wolfson_wm9713_specific, .build_3d = patch_wolfson_wm9713_3d, #ifdef CONFIG_PM @@ -958,10 +952,13 @@ static int patch_sigmatel_stac9708_3d(struct snd_ac97 * ac97) } static const struct snd_kcontrol_new snd_ac97_sigmatel_4speaker = -AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); +AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", + AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); +/* "Sigmatel " removed due to excessive name length: */ static const struct snd_kcontrol_new snd_ac97_sigmatel_phaseinvert = -AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); +AC97_SINGLE("Surround Phase Inversion Playback Switch", + AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); static const struct snd_kcontrol_new snd_ac97_sigmatel_controls[] = { AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), @@ -988,7 +985,7 @@ static int patch_sigmatel_stac97xx_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { +static const struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { .build_3d = patch_sigmatel_stac9700_3d, .build_specific = patch_sigmatel_stac97xx_specific }; @@ -1035,7 +1032,7 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) return patch_sigmatel_stac97xx_specific(ac97); } -static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { +static const struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { .build_3d = patch_sigmatel_stac9708_3d, .build_specific = patch_sigmatel_stac9708_specific }; @@ -1264,7 +1261,7 @@ static int patch_sigmatel_stac9758_specific(struct snd_ac97 *ac97) return 0; } -static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = { +static const struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = { .build_3d = patch_sigmatel_stac9700_3d, .build_specific = patch_sigmatel_stac9758_specific }; @@ -1339,7 +1336,7 @@ static int patch_cirrus_build_spdif(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_cirrus_ops = { +static const struct snd_ac97_build_ops patch_cirrus_ops = { .build_spdif = patch_cirrus_build_spdif }; @@ -1396,7 +1393,7 @@ static int patch_conexant_build_spdif(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_conexant_ops = { +static const struct snd_ac97_build_ops patch_conexant_ops = { .build_spdif = patch_conexant_build_spdif }; @@ -1572,7 +1569,7 @@ static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int } } -static struct snd_ac97_build_ops patch_ad1881_build_ops = { +static const struct snd_ac97_build_ops patch_ad1881_build_ops = { #ifdef CONFIG_PM .resume = ad18xx_resume #endif @@ -1659,7 +1656,7 @@ static int patch_ad1885_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_ad1885_build_ops = { +static const struct snd_ac97_build_ops patch_ad1885_build_ops = { .build_specific = &patch_ad1885_specific, #ifdef CONFIG_PM .resume = ad18xx_resume @@ -1686,7 +1683,7 @@ static int patch_ad1886_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_ad1886_build_ops = { +static const struct snd_ac97_build_ops patch_ad1886_build_ops = { .build_specific = &patch_ad1886_specific, #ifdef CONFIG_PM .resume = ad18xx_resume @@ -1864,11 +1861,14 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ + 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; @@ -1890,7 +1890,7 @@ static int patch_ad1981a_specific(struct snd_ac97 * ac97) ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); } -static struct snd_ac97_build_ops patch_ad1981a_build_ops = { +static const struct snd_ac97_build_ops patch_ad1981a_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1981a_specific, #ifdef CONFIG_PM @@ -1909,6 +1909,7 @@ static unsigned int ad1981_jacks_whitelist[] = { 0x103c0944, /* HP nc6220 */ 0x103c0934, /* HP nc8220 */ 0x103c006d, /* HP nx9105 */ + 0x103c300d, /* HP Compaq dc5100 SFF(PT003AW) */ 0x17340088, /* FSC Scenic-W */ 0 /* end */ }; @@ -1945,7 +1946,7 @@ static int patch_ad1981b_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); } -static struct snd_ac97_build_ops patch_ad1981b_build_ops = { +static const struct snd_ac97_build_ops patch_ad1981b_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1981b_specific, #ifdef CONFIG_PM @@ -2054,8 +2055,9 @@ static const struct snd_kcontrol_new snd_ac97_ad1888_controls[] = { .get = snd_ac97_ad1888_lohpsel_get, .put = snd_ac97_ad1888_lohpsel_put }, - AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, 2, 1, 1), - AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, 12, 1, 1), + AC97_SINGLE("V_REFOUT Enable", AC97_AD_MISC, AC97_AD_VREFD_SHIFT, 1, 1), + AC97_SINGLE("High Pass Filter Enable", AC97_AD_TEST2, + AC97_AD_HPFD_SHIFT, 1, 1), AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2083,7 +2085,7 @@ static int patch_ad1888_specific(struct snd_ac97 *ac97) 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 = { +static const struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1888_specific, #ifdef CONFIG_PM @@ -2132,7 +2134,7 @@ static int patch_ad1980_specific(struct snd_ac97 *ac97) return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); } -static struct snd_ac97_build_ops patch_ad1980_build_ops = { +static const struct snd_ac97_build_ops patch_ad1980_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1980_specific, #ifdef CONFIG_PM @@ -2247,7 +2249,7 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1985_controls)); } -static struct snd_ac97_build_ops patch_ad1985_build_ops = { +static const struct snd_ac97_build_ops patch_ad1985_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1985_specific, #ifdef CONFIG_PM @@ -2539,7 +2541,7 @@ static int patch_ad1986_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1985_controls)); } -static struct snd_ac97_build_ops patch_ad1986_build_ops = { +static const struct snd_ac97_build_ops patch_ad1986_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1986_specific, #ifdef CONFIG_PM @@ -2560,6 +2562,14 @@ static int patch_ad1986(struct snd_ac97 * ac97) return 0; } +/* + * realtek ALC203: use mono-out for pin 37 + */ +static int patch_alc203(struct snd_ac97 *ac97) +{ + snd_ac97_update_bits(ac97, 0x7a, 0x400, 0x400); + return 0; +} /* * realtek ALC65x/850 codecs @@ -2585,6 +2595,21 @@ static void alc650_update_jacks(struct snd_ac97 *ac97) shared ? 0 : 0x100); } +static int alc650_swap_surround_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); + struct snd_pcm_chmap *map = ac97->chmaps[SNDRV_PCM_STREAM_PLAYBACK]; + + if (map) { + if (ucontrol->value.integer.value[0]) + map->chmap = snd_pcm_std_chmaps; + else + map->chmap = snd_pcm_alt_chmaps; + } + return snd_ac97_put_volsw(kcontrol, ucontrol); +} + static const struct snd_kcontrol_new 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), @@ -2598,7 +2623,14 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc650[] = { /* 9: Line-In/Surround share */ /* 10: Mic/CLFE share */ /* 11-13: in IEC958 controls */ - AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Swap Surround Slot", + .info = snd_ac97_info_volsw, + .get = snd_ac97_get_volsw, + .put = alc650_swap_surround_put, + .private_value = AC97_SINGLE_VALUE(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), @@ -2636,7 +2668,7 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_alc650_ops = { +static const struct snd_ac97_build_ops patch_alc650_ops = { .build_specific = patch_alc650_specific, .update_jacks = alc650_update_jacks }; @@ -2788,7 +2820,7 @@ static int patch_alc655_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_alc655_ops = { +static const struct snd_ac97_build_ops patch_alc655_ops = { .build_specific = patch_alc655_specific, .update_jacks = alc655_update_jacks }; @@ -2824,6 +2856,8 @@ static int patch_alc655(struct snd_ac97 * ac97) val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ else val |= (1 << 1); /* Pin 47 is spdif input pin */ + /* this seems missing on some hardwares */ + ac97->ext_id |= AC97_EI_SPDIF; } val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); @@ -2898,7 +2932,7 @@ static int patch_alc850_specific(struct snd_ac97 *ac97) return 0; } -static struct snd_ac97_build_ops patch_alc850_ops = { +static const struct snd_ac97_build_ops patch_alc850_ops = { .build_specific = patch_alc850_specific, .update_jacks = alc850_update_jacks }; @@ -2938,6 +2972,49 @@ static int patch_alc850(struct snd_ac97 *ac97) return 0; } +static int patch_aztech_azf3328_specific(struct snd_ac97 *ac97) +{ + struct snd_kcontrol *kctl_3d_center = + snd_ac97_find_mixer_ctl(ac97, "3D Control - Center"); + struct snd_kcontrol *kctl_3d_depth = + snd_ac97_find_mixer_ctl(ac97, "3D Control - Depth"); + + /* + * 3D register is different from AC97 standard layout + * (also do some renaming, to resemble Windows driver naming) + */ + if (kctl_3d_center) { + kctl_3d_center->private_value = + AC97_SINGLE_VALUE(AC97_3D_CONTROL, 1, 0x07, 0); + snd_ac97_rename_vol_ctl(ac97, + "3D Control - Center", "3D Control - Width" + ); + } + if (kctl_3d_depth) + kctl_3d_depth->private_value = + AC97_SINGLE_VALUE(AC97_3D_CONTROL, 8, 0x03, 0); + + /* Aztech Windows driver calls the + equivalent control "Modem Playback", thus rename it: */ + snd_ac97_rename_vol_ctl(ac97, + "Master Mono Playback", "Modem Playback" + ); + snd_ac97_rename_vol_ctl(ac97, + "Headphone Playback", "FM Synth Playback" + ); + + return 0; +} + +static const struct snd_ac97_build_ops patch_aztech_azf3328_ops = { + .build_specific = patch_aztech_azf3328_specific +}; + +static int patch_aztech_azf3328(struct snd_ac97 *ac97) +{ + ac97->build_ops = &patch_aztech_azf3328_ops; + return 0; +} /* * C-Media CM97xx codecs @@ -2960,7 +3037,7 @@ static int patch_cm9738_specific(struct snd_ac97 * 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 = { +static const struct snd_ac97_build_ops patch_cm9738_ops = { .build_specific = patch_cm9738_specific, .update_jacks = cm9738_update_jacks }; @@ -3051,7 +3128,7 @@ static int patch_cm9739_post_spdif(struct snd_ac97 * 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 = { +static const struct snd_ac97_build_ops patch_cm9739_ops = { .build_specific = patch_cm9739_specific, .build_post_spdif = patch_cm9739_post_spdif, .update_jacks = cm9739_update_jacks @@ -3225,7 +3302,7 @@ static int patch_cm9761_specific(struct snd_ac97 * ac97) return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); } -static struct snd_ac97_build_ops patch_cm9761_ops = { +static const struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, .build_post_spdif = patch_cm9761_post_spdif, .update_jacks = cm9761_update_jacks @@ -3321,7 +3398,7 @@ static int patch_cm9780_specific(struct snd_ac97 *ac97) return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); } -static struct snd_ac97_build_ops patch_cm9780_ops = { +static const struct snd_ac97_build_ops patch_cm9780_ops = { .build_specific = patch_cm9780_specific, .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ }; @@ -3400,7 +3477,8 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, sctl = snd_ac97_find_mixer_ctl(ac97, *s); if (!sctl) { - snd_printdd("Cannot find slave %s, skipped\n", *s); + dev_dbg(ac97->bus->card->dev, + "Cannot find slave %s, skipped\n", *s); continue; } err = snd_ctl_add_slave(kctl, sctl); @@ -3441,7 +3519,7 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_vt1616_ops = { +static const struct snd_ac97_build_ops patch_vt1616_ops = { .build_specific = patch_vt1616_specific }; @@ -3457,7 +3535,7 @@ static int patch_vt1616(struct snd_ac97 * ac97) /* * unfortunately, the vt1617a stashes the twiddlers required for - * nooding the i/o jacks on 2 different regs. * thameans that we cant + * noodling the i/o jacks on 2 different regs. that means that we can't * use the easy way provided by AC97_ENUM_DOUBLE() we have to write * are own funcs. * @@ -3490,7 +3568,7 @@ static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol, pac97 = snd_kcontrol_chip(kcontrol); /* grab codec handle */ - /* grab our desirec bits, then mash them together in a manner + /* grab our desired bits, then mash them together in a manner * consistent with Table 6 on page 17 in the 1617a docs */ usSM51 = snd_ac97_read(pac97, 0x7a) >> 14; @@ -3540,7 +3618,7 @@ static const struct snd_kcontrol_new snd_ac97_controls_vt1617a[] = { }, }; -int patch_vt1617a(struct snd_ac97 * ac97) +static int patch_vt1617a(struct snd_ac97 * ac97) { int err = 0; int val; @@ -3568,6 +3646,200 @@ int patch_vt1617a(struct snd_ac97 * ac97) return err; } +/* VIA VT1618 8 CHANNEL AC97 CODEC + * + * VIA implements 'Smart 5.1' completely differently on the 1618 than + * it does on the 1617a. awesome! They seem to have sourced this + * particular revision of the technology from somebody else, it's + * called Universal Audio Jack and it shows up on some other folk's chips + * as well. + * + * ordering in this list reflects vt1618 docs for Reg 60h and + * the block diagram, DACs are as follows: + * + * OUT_O -> Front, + * OUT_1 -> Surround, + * OUT_2 -> C/LFE + * + * Unlike the 1617a, each OUT has a consistent set of mappings + * for all bitpatterns other than 00: + * + * 01 Unmixed Output + * 10 Line In + * 11 Mic In + * + * Special Case of 00: + * + * OUT_0 Mixed Output + * OUT_1 Reserved + * OUT_2 Reserved + * + * I have no idea what the hell Reserved does, but on an MSI + * CN700T, i have to set it to get 5.1 output - YMMV, bad + * shit may happen. + * + * If other chips use Universal Audio Jack, then this code might be applicable + * to them. + */ + +struct vt1618_uaj_item { + unsigned short mask; + unsigned short shift; + const char *items[4]; +}; + +/* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */ + +static struct vt1618_uaj_item vt1618_uaj[3] = { + { + /* speaker jack */ + .mask = 0x03, + .shift = 0, + .items = { + "Speaker Out", "DAC Unmixed Out", "Line In", "Mic In" + } + }, + { + /* line jack */ + .mask = 0x0c, + .shift = 2, + .items = { + "Surround Out", "DAC Unmixed Out", "Line In", "Mic In" + } + }, + { + /* mic jack */ + .mask = 0x30, + .shift = 4, + .items = { + "Center LFE Out", "DAC Unmixed Out", "Line In", "Mic In" + }, + }, +}; + +static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return ac97_enum_text_info(kcontrol, uinfo, + vt1618_uaj[kcontrol->private_value].items, + 4); +} + +/* All of the vt1618 Universal Audio Jack twiddlers are on + * Vendor Defined Register 0x60, page 0. The bits, and thus + * the mask, are the only thing that changes + */ +static int snd_ac97_vt1618_UAJ_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned short datpag, uaj; + struct snd_ac97 *pac97 = snd_kcontrol_chip(kcontrol); + + mutex_lock(&pac97->page_mutex); + + datpag = snd_ac97_read(pac97, AC97_INT_PAGING) & AC97_PAGE_MASK; + snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, 0); + + uaj = snd_ac97_read(pac97, 0x60) & + vt1618_uaj[kcontrol->private_value].mask; + + snd_ac97_update_bits(pac97, AC97_INT_PAGING, AC97_PAGE_MASK, datpag); + mutex_unlock(&pac97->page_mutex); + + ucontrol->value.enumerated.item[0] = uaj >> + vt1618_uaj[kcontrol->private_value].shift; + + return 0; +} + +static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return ac97_update_bits_page(snd_kcontrol_chip(kcontrol), 0x60, + vt1618_uaj[kcontrol->private_value].mask, + ucontrol->value.enumerated.item[0]<< + vt1618_uaj[kcontrol->private_value].shift, + 0); +} + +/* config aux in jack - not found on 3 jack motherboards or soundcards */ + +static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *txt_aux[] = {"Aux In", "Back Surr Out"}; + + return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2); +} + +static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = + (snd_ac97_read(snd_kcontrol_chip(kcontrol), 0x5c) & 0x0008)>>3; + return 0; +} + +static int snd_ac97_vt1618_aux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* toggle surround rear dac power */ + + snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x5c, 0x0008, + ucontrol->value.enumerated.item[0] << 3); + + /* toggle aux in surround rear out jack */ + + return snd_ac97_update_bits(snd_kcontrol_chip(kcontrol), 0x76, 0x0008, + ucontrol->value.enumerated.item[0] << 3); +} + +static const struct snd_kcontrol_new snd_ac97_controls_vt1618[] = { + AC97_SINGLE("Exchange Center/LFE", 0x5a, 8, 1, 0), + AC97_SINGLE("DC Offset", 0x5a, 10, 1, 0), + AC97_SINGLE("Soft Mute", 0x5c, 0, 1, 1), + AC97_SINGLE("Headphone Amp", 0x5c, 5, 1, 1), + AC97_DOUBLE("Back Surr Volume", 0x5e, 8, 0, 31, 1), + AC97_SINGLE("Back Surr Switch", 0x5e, 15, 1, 1), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Speaker Jack Mode", + .info = snd_ac97_vt1618_UAJ_info, + .get = snd_ac97_vt1618_UAJ_get, + .put = snd_ac97_vt1618_UAJ_put, + .private_value = 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line Jack Mode", + .info = snd_ac97_vt1618_UAJ_info, + .get = snd_ac97_vt1618_UAJ_get, + .put = snd_ac97_vt1618_UAJ_put, + .private_value = 1 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Jack Mode", + .info = snd_ac97_vt1618_UAJ_info, + .get = snd_ac97_vt1618_UAJ_get, + .put = snd_ac97_vt1618_UAJ_put, + .private_value = 2 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Aux Jack Mode", + .info = snd_ac97_vt1618_aux_info, + .get = snd_ac97_vt1618_aux_get, + .put = snd_ac97_vt1618_aux_put, + } +}; + +static int patch_vt1618(struct snd_ac97 *ac97) +{ + return patch_build_controls(ac97, snd_ac97_controls_vt1618, + ARRAY_SIZE(snd_ac97_controls_vt1618)); +} + /* */ static void it2646_update_jacks(struct snd_ac97 *ac97) @@ -3601,7 +3873,7 @@ static int patch_it2646_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_it2646_ops = { +static const struct snd_ac97_build_ops patch_it2646_ops = { .build_specific = patch_it2646_specific, .update_jacks = it2646_update_jacks }; @@ -3635,7 +3907,7 @@ static int patch_si3036_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_si3036_ops = { +static const struct snd_ac97_build_ops patch_si3036_ops = { .build_specific = patch_si3036_specific, }; @@ -3702,7 +3974,7 @@ static int patch_ucb1400_specific(struct snd_ac97 * ac97) return 0; } -static struct snd_ac97_build_ops patch_ucb1400_ops = { +static const struct snd_ac97_build_ops patch_ucb1400_ops = { .build_specific = patch_ucb1400_specific, }; |
