diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-04-13 08:32:57 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-05-29 04:00:48 -0400 |
commit | eb8caf30f4c059ddfdfa32b6034549622953db6f (patch) | |
tree | 994ff6f1a8b19fb8914af3eae6035fd32b834c0f /sound/pci/ac97/ac97_patch.c | |
parent | 267cdf4036ed9e8565a7d909fdf854b9c7e1c5ff (diff) |
[ALSA] Improve the shared-jack handling on ac97
AC97 Codec
The handling of shared surround/clfe output jacks with line/mic-in
on some AC97 codecs is improved.
Instead of 'Line-In As Surround' or 'Mic As Center/LFE' switch, two
new enum controls are introduced: 'Channel Mode' and 'Surround Jack Mode'.
The formar changes the current output mode among 2, 4 and 6-channels.
The latter controls whether the jacks are shared or independent.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ac97/ac97_patch.c')
-rw-r--r-- | sound/pci/ac97/ac97_patch.c | 426 |
1 files changed, 236 insertions, 190 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 473840d431b3..7f16c306165b 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -64,6 +64,116 @@ static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned shor | |||
64 | return ret; | 64 | return ret; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* | ||
68 | * shared line-in/mic controls | ||
69 | */ | ||
70 | static int ac97_enum_text_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo, | ||
71 | const char **texts, unsigned int nums) | ||
72 | { | ||
73 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
74 | uinfo->count = 1; | ||
75 | uinfo->value.enumerated.items = nums; | ||
76 | if (uinfo->value.enumerated.item > nums - 1) | ||
77 | uinfo->value.enumerated.item = nums - 1; | ||
78 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int ac97_surround_jack_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
83 | { | ||
84 | static const char *texts[] = { "Shared", "Independent" }; | ||
85 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); | ||
86 | } | ||
87 | |||
88 | static int ac97_surround_jack_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
89 | { | ||
90 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
91 | |||
92 | ucontrol->value.enumerated.item[0] = ac97->indep_surround; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int ac97_surround_jack_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
97 | { | ||
98 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
99 | unsigned char indep = !!ucontrol->value.enumerated.item[0]; | ||
100 | |||
101 | if (indep != ac97->indep_surround) { | ||
102 | ac97->indep_surround = indep; | ||
103 | if (ac97->build_ops->update_jacks) | ||
104 | ac97->build_ops->update_jacks(ac97); | ||
105 | return 1; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static int ac97_channel_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
111 | { | ||
112 | static const char *texts[] = { "2ch", "4ch", "6ch" }; | ||
113 | if (kcontrol->private_value) | ||
114 | return ac97_enum_text_info(kcontrol, uinfo, texts, 2); /* 4ch only */ | ||
115 | return ac97_enum_text_info(kcontrol, uinfo, texts, 3); | ||
116 | } | ||
117 | |||
118 | static int ac97_channel_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
119 | { | ||
120 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
121 | |||
122 | ucontrol->value.enumerated.item[0] = ac97->channel_mode; | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int ac97_channel_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
127 | { | ||
128 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
129 | unsigned char mode = ucontrol->value.enumerated.item[0]; | ||
130 | |||
131 | if (mode != ac97->channel_mode) { | ||
132 | ac97->channel_mode = mode; | ||
133 | if (ac97->build_ops->update_jacks) | ||
134 | ac97->build_ops->update_jacks(ac97); | ||
135 | return 1; | ||
136 | } | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | #define AC97_SURROUND_JACK_MODE_CTL \ | ||
141 | { \ | ||
142 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
143 | .name = "Surround Jack Mode", \ | ||
144 | .info = ac97_surround_jack_mode_info, \ | ||
145 | .get = ac97_surround_jack_mode_get, \ | ||
146 | .put = ac97_surround_jack_mode_put, \ | ||
147 | } | ||
148 | #define AC97_CHANNEL_MODE_CTL \ | ||
149 | { \ | ||
150 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
151 | .name = "Channel Mode", \ | ||
152 | .info = ac97_channel_mode_info, \ | ||
153 | .get = ac97_channel_mode_get, \ | ||
154 | .put = ac97_channel_mode_put, \ | ||
155 | } | ||
156 | #define AC97_CHANNEL_MODE_4CH_CTL \ | ||
157 | { \ | ||
158 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
159 | .name = "Channel Mode", \ | ||
160 | .info = ac97_channel_mode_info, \ | ||
161 | .get = ac97_channel_mode_get, \ | ||
162 | .put = ac97_channel_mode_put, \ | ||
163 | .private_value = 1, \ | ||
164 | } | ||
165 | |||
166 | static inline int is_shared_linein(ac97_t *ac97) | ||
167 | { | ||
168 | return ! ac97->indep_surround && ac97->channel_mode >= 1; | ||
169 | } | ||
170 | |||
171 | static inline int is_shared_micin(ac97_t *ac97) | ||
172 | { | ||
173 | return ! ac97->indep_surround && ac97->channel_mode >= 2; | ||
174 | } | ||
175 | |||
176 | |||
67 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ | 177 | /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
68 | 178 | ||
69 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ | 179 | /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ |
@@ -1390,6 +1500,16 @@ static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_va | |||
1390 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); | 1500 | AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); |
1391 | } | 1501 | } |
1392 | 1502 | ||
1503 | static void ad1888_update_jacks(ac97_t *ac97) | ||
1504 | { | ||
1505 | /* shared Line-In */ | ||
1506 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 12, | ||
1507 | is_shared_linein(ac97) ? 0 : 1 << 12); | ||
1508 | /* shared Mic */ | ||
1509 | snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << 11, | ||
1510 | is_shared_micin(ac97) ? 0 : 1 << 13); | ||
1511 | } | ||
1512 | |||
1393 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | 1513 | static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { |
1394 | { | 1514 | { |
1395 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1515 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -1406,8 +1526,13 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { | |||
1406 | .get = snd_ac97_ad1888_downmix_get, | 1526 | .get = snd_ac97_ad1888_downmix_get, |
1407 | .put = snd_ac97_ad1888_downmix_put | 1527 | .put = snd_ac97_ad1888_downmix_put |
1408 | }, | 1528 | }, |
1529 | #if 0 | ||
1409 | AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), | 1530 | AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), |
1410 | AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), | 1531 | AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), |
1532 | #else | ||
1533 | AC97_SURROUND_JACK_MODE_CTL, | ||
1534 | AC97_CHANNEL_MODE_CTL, | ||
1535 | #endif | ||
1411 | }; | 1536 | }; |
1412 | 1537 | ||
1413 | static int patch_ad1888_specific(ac97_t *ac97) | 1538 | static int patch_ad1888_specific(ac97_t *ac97) |
@@ -1422,8 +1547,9 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { | |||
1422 | .build_post_spdif = patch_ad198x_post_spdif, | 1547 | .build_post_spdif = patch_ad198x_post_spdif, |
1423 | .build_specific = patch_ad1888_specific, | 1548 | .build_specific = patch_ad1888_specific, |
1424 | #ifdef CONFIG_PM | 1549 | #ifdef CONFIG_PM |
1425 | .resume = ad18xx_resume | 1550 | .resume = ad18xx_resume, |
1426 | #endif | 1551 | #endif |
1552 | .update_jacks = ad1888_update_jacks, | ||
1427 | }; | 1553 | }; |
1428 | 1554 | ||
1429 | int patch_ad1888(ac97_t * ac97) | 1555 | int patch_ad1888(ac97_t * ac97) |
@@ -1521,31 +1647,25 @@ int patch_ad1985(ac97_t * ac97) | |||
1521 | /* | 1647 | /* |
1522 | * realtek ALC65x/850 codecs | 1648 | * realtek ALC65x/850 codecs |
1523 | */ | 1649 | */ |
1524 | static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1650 | static void alc650_update_jacks(ac97_t *ac97) |
1525 | { | ||
1526 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1527 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1532 | { | 1651 | { |
1533 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1652 | int shared; |
1534 | int change, val; | 1653 | |
1535 | val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); | 1654 | /* shared Line-In */ |
1536 | change = (ucontrol->value.integer.value[0] != val); | 1655 | shared = is_shared_linein(ac97); |
1537 | if (change) { | 1656 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 9, |
1538 | /* disable/enable vref */ | 1657 | shared ? (1 << 9) : 0); |
1539 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1658 | /* update shared Mic */ |
1540 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1659 | shared = is_shared_micin(ac97); |
1541 | /* turn on/off center-on-mic */ | 1660 | /* disable/enable vref */ |
1542 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1661 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1543 | ucontrol->value.integer.value[0] ? (1 << 10) : 0); | 1662 | shared ? (1 << 12) : 0); |
1544 | /* GPIO0 high for mic */ | 1663 | /* turn on/off center-on-mic */ |
1545 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, | 1664 | snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1546 | ucontrol->value.integer.value[0] ? 0 : 0x100); | 1665 | shared ? (1 << 10) : 0); |
1547 | } | 1666 | /* GPIO0 high for mic */ |
1548 | return change; | 1667 | snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, |
1668 | shared ? 0 : 0x100); | ||
1549 | } | 1669 | } |
1550 | 1670 | ||
1551 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | 1671 | static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { |
@@ -1558,8 +1678,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1558 | /* 6: Independent Master Volume Right */ | 1678 | /* 6: Independent Master Volume Right */ |
1559 | /* 7: Independent Master Volume Left */ | 1679 | /* 7: Independent Master Volume Left */ |
1560 | /* 8: reserved */ | 1680 | /* 8: reserved */ |
1561 | AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), | 1681 | /* 9: Line-In/Surround share */ |
1562 | /* 10: mic, see below */ | 1682 | /* 10: Mic/CLFE share */ |
1563 | /* 11-13: in IEC958 controls */ | 1683 | /* 11-13: in IEC958 controls */ |
1564 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), | 1684 | AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), |
1565 | #if 0 /* always set in patch_alc650 */ | 1685 | #if 0 /* always set in patch_alc650 */ |
@@ -1570,14 +1690,8 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { | |||
1570 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), | 1690 | AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), |
1571 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), | 1691 | AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), |
1572 | #endif | 1692 | #endif |
1573 | { | 1693 | AC97_SURROUND_JACK_MODE_CTL, |
1574 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1694 | AC97_CHANNEL_MODE_CTL, |
1575 | .name = "Mic As Center/LFE", | ||
1576 | .info = snd_ac97_info_volsw, | ||
1577 | .get = snd_ac97_alc650_mic_get, | ||
1578 | .put = snd_ac97_alc650_mic_put, | ||
1579 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1580 | }, | ||
1581 | }; | 1695 | }; |
1582 | 1696 | ||
1583 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { | 1697 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { |
@@ -1601,7 +1715,8 @@ static int patch_alc650_specific(ac97_t * ac97) | |||
1601 | } | 1715 | } |
1602 | 1716 | ||
1603 | static struct snd_ac97_build_ops patch_alc650_ops = { | 1717 | static struct snd_ac97_build_ops patch_alc650_ops = { |
1604 | .build_specific = patch_alc650_specific | 1718 | .build_specific = patch_alc650_specific, |
1719 | .update_jacks = alc650_update_jacks | ||
1605 | }; | 1720 | }; |
1606 | 1721 | ||
1607 | int patch_alc650(ac97_t * ac97) | 1722 | int patch_alc650(ac97_t * ac97) |
@@ -1659,37 +1774,27 @@ int patch_alc650(ac97_t * ac97) | |||
1659 | return 0; | 1774 | return 0; |
1660 | } | 1775 | } |
1661 | 1776 | ||
1662 | static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1777 | static void alc655_update_jacks(ac97_t *ac97) |
1663 | { | ||
1664 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1665 | ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; | ||
1666 | return 0; | ||
1667 | } | ||
1668 | |||
1669 | static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1670 | { | 1778 | { |
1671 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1779 | int shared; |
1672 | 1780 | ||
1781 | /* shared Line-In */ | ||
1782 | shared = is_shared_linein(ac97); | ||
1783 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 9, | ||
1784 | shared ? (1 << 9) : 0, 0); | ||
1785 | /* update shared mic */ | ||
1786 | shared = is_shared_micin(ac97); | ||
1673 | /* misc control; vrefout disable */ | 1787 | /* misc control; vrefout disable */ |
1674 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, | 1788 | snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, |
1675 | ucontrol->value.integer.value[0] ? (1 << 12) : 0); | 1789 | shared ? (1 << 12) : 0); |
1676 | return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, | 1790 | ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10, |
1677 | ucontrol->value.integer.value[0] ? (1 << 10) : 0, | 1791 | shared ? (1 << 10) : 0, 0); |
1678 | 0); | ||
1679 | } | 1792 | } |
1680 | 1793 | ||
1681 | |||
1682 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { | 1794 | static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { |
1683 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1795 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1684 | AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0), | 1796 | AC97_SURROUND_JACK_MODE_CTL, |
1685 | { | 1797 | AC97_CHANNEL_MODE_CTL, |
1686 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1687 | .name = "Mic As Center/LFE", | ||
1688 | .info = snd_ac97_info_volsw, | ||
1689 | .get = snd_ac97_alc655_mic_get, | ||
1690 | .put = snd_ac97_alc655_mic_put, | ||
1691 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1692 | }, | ||
1693 | }; | 1798 | }; |
1694 | 1799 | ||
1695 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | 1800 | static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
@@ -1759,7 +1864,8 @@ static int patch_alc655_specific(ac97_t * ac97) | |||
1759 | } | 1864 | } |
1760 | 1865 | ||
1761 | static struct snd_ac97_build_ops patch_alc655_ops = { | 1866 | static struct snd_ac97_build_ops patch_alc655_ops = { |
1762 | .build_specific = patch_alc655_specific | 1867 | .build_specific = patch_alc655_specific, |
1868 | .update_jacks = alc655_update_jacks | ||
1763 | }; | 1869 | }; |
1764 | 1870 | ||
1765 | int patch_alc655(ac97_t * ac97) | 1871 | int patch_alc655(ac97_t * ac97) |
@@ -1798,63 +1904,32 @@ int patch_alc655(ac97_t * ac97) | |||
1798 | #define AC97_ALC850_JACK_SELECT 0x76 | 1904 | #define AC97_ALC850_JACK_SELECT 0x76 |
1799 | #define AC97_ALC850_MISC1 0x7a | 1905 | #define AC97_ALC850_MISC1 0x7a |
1800 | 1906 | ||
1801 | static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | 1907 | static void alc850_update_jacks(ac97_t *ac97) |
1802 | { | 1908 | { |
1803 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 1909 | int shared; |
1804 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2; | 1910 | |
1805 | return 0; | 1911 | /* shared Line-In */ |
1806 | } | 1912 | shared = is_shared_linein(ac97); |
1807 | |||
1808 | static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1809 | { | ||
1810 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1811 | |||
1812 | /* SURR 1kOhm (bit4), Amp (bit5) */ | 1913 | /* SURR 1kOhm (bit4), Amp (bit5) */ |
1813 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), | 1914 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5), |
1814 | ucontrol->value.integer.value[0] ? (1<<5) : (1<<4)); | 1915 | shared ? (1<<5) : (1<<4)); |
1815 | /* LINE-IN = 0, SURROUND = 2 */ | 1916 | /* LINE-IN = 0, SURROUND = 2 */ |
1816 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, | 1917 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12, |
1817 | ucontrol->value.integer.value[0] ? (2<<12) : (0<<12)); | 1918 | shared ? (2<<12) : (0<<12)); |
1818 | } | 1919 | /* update shared mic */ |
1819 | 1920 | shared = is_shared_micin(ac97); | |
1820 | static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1821 | { | ||
1822 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1823 | ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2; | ||
1824 | return 0; | ||
1825 | } | ||
1826 | |||
1827 | static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1828 | { | ||
1829 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1830 | |||
1831 | /* Vref disable (bit12), 1kOhm (bit13) */ | 1921 | /* Vref disable (bit12), 1kOhm (bit13) */ |
1832 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), | 1922 | snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13), |
1833 | ucontrol->value.integer.value[0] ? (1<<12) : (1<<13)); | 1923 | shared ? (1<<12) : (1<<13)); |
1834 | /* MIC-IN = 1, CENTER-LFE = 2 */ | 1924 | /* MIC-IN = 1, CENTER-LFE = 2 */ |
1835 | return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, | 1925 | snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4, |
1836 | ucontrol->value.integer.value[0] ? (2<<4) : (1<<4)); | 1926 | shared ? (2<<4) : (1<<4)); |
1837 | } | 1927 | } |
1838 | 1928 | ||
1839 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { | 1929 | static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { |
1840 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), | 1930 | AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0), |
1841 | { | 1931 | AC97_SURROUND_JACK_MODE_CTL, |
1842 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1932 | AC97_CHANNEL_MODE_CTL, |
1843 | .name = "Line-In As Surround", | ||
1844 | .info = snd_ac97_info_volsw, | ||
1845 | .get = ac97_alc850_surround_get, | ||
1846 | .put = ac97_alc850_surround_put, | ||
1847 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1848 | }, | ||
1849 | { | ||
1850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1851 | .name = "Mic As Center/LFE", | ||
1852 | .info = snd_ac97_info_volsw, | ||
1853 | .get = ac97_alc850_mic_get, | ||
1854 | .put = ac97_alc850_mic_put, | ||
1855 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
1856 | }, | ||
1857 | |||
1858 | }; | 1933 | }; |
1859 | 1934 | ||
1860 | static int patch_alc850_specific(ac97_t *ac97) | 1935 | static int patch_alc850_specific(ac97_t *ac97) |
@@ -1871,7 +1946,8 @@ static int patch_alc850_specific(ac97_t *ac97) | |||
1871 | } | 1946 | } |
1872 | 1947 | ||
1873 | static struct snd_ac97_build_ops patch_alc850_ops = { | 1948 | static struct snd_ac97_build_ops patch_alc850_ops = { |
1874 | .build_specific = patch_alc850_specific | 1949 | .build_specific = patch_alc850_specific, |
1950 | .update_jacks = alc850_update_jacks | ||
1875 | }; | 1951 | }; |
1876 | 1952 | ||
1877 | int patch_alc850(ac97_t *ac97) | 1953 | int patch_alc850(ac97_t *ac97) |
@@ -1911,9 +1987,17 @@ int patch_alc850(ac97_t *ac97) | |||
1911 | /* | 1987 | /* |
1912 | * C-Media CM97xx codecs | 1988 | * C-Media CM97xx codecs |
1913 | */ | 1989 | */ |
1990 | static void cm9738_update_jacks(ac97_t *ac97) | ||
1991 | { | ||
1992 | /* shared Line-In */ | ||
1993 | snd_ac97_update_bits(ac97, AC97_CM9738_VENDOR_CTRL, 1 << 10, | ||
1994 | is_shared_linein(ac97) ? (1 << 10) : 0); | ||
1995 | } | ||
1996 | |||
1914 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { | 1997 | static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { |
1915 | AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), | ||
1916 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), | 1998 | AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), |
1999 | AC97_SURROUND_JACK_MODE_CTL, | ||
2000 | AC97_CHANNEL_MODE_4CH_CTL, | ||
1917 | }; | 2001 | }; |
1918 | 2002 | ||
1919 | static int patch_cm9738_specific(ac97_t * ac97) | 2003 | static int patch_cm9738_specific(ac97_t * ac97) |
@@ -1922,7 +2006,8 @@ static int patch_cm9738_specific(ac97_t * ac97) | |||
1922 | } | 2006 | } |
1923 | 2007 | ||
1924 | static struct snd_ac97_build_ops patch_cm9738_ops = { | 2008 | static struct snd_ac97_build_ops patch_cm9738_ops = { |
1925 | .build_specific = patch_cm9738_specific | 2009 | .build_specific = patch_cm9738_specific, |
2010 | .update_jacks = cm9738_update_jacks | ||
1926 | }; | 2011 | }; |
1927 | 2012 | ||
1928 | int patch_cm9738(ac97_t * ac97) | 2013 | int patch_cm9738(ac97_t * ac97) |
@@ -1986,34 +2071,19 @@ static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { | |||
1986 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ | 2071 | /* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ |
1987 | }; | 2072 | }; |
1988 | 2073 | ||
1989 | static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2074 | static void cm9739_update_jacks(ac97_t *ac97) |
1990 | { | ||
1991 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
1992 | if (ac97->regs[AC97_CM9739_MULTI_CHAN] & 0x1000) | ||
1993 | ucontrol->value.integer.value[0] = 1; | ||
1994 | else | ||
1995 | ucontrol->value.integer.value[0] = 0; | ||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | static int snd_ac97_cm9739_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2000 | { | 2075 | { |
2001 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2076 | /* shared Line-In */ |
2002 | return snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | 2077 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 1 << 10, |
2003 | ucontrol->value.integer.value[0] ? | 2078 | is_shared_linein(ac97) ? (1 << 10) : 0); |
2004 | 0x1000 : 0x2000); | 2079 | /* shared Mic */ |
2080 | snd_ac97_update_bits(ac97, AC97_CM9739_MULTI_CHAN, 0x3000, | ||
2081 | is_shared_micin(ac97) ? 0x1000 : 0x2000); | ||
2005 | } | 2082 | } |
2006 | 2083 | ||
2007 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { | 2084 | static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { |
2008 | AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), | 2085 | AC97_SURROUND_JACK_MODE_CTL, |
2009 | { | 2086 | AC97_CHANNEL_MODE_CTL, |
2010 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2011 | .name = "Mic As Center/LFE", | ||
2012 | .info = snd_ac97_info_volsw, | ||
2013 | .get = snd_ac97_cm9739_center_mic_get, | ||
2014 | .put = snd_ac97_cm9739_center_mic_put, | ||
2015 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2016 | }, | ||
2017 | }; | 2087 | }; |
2018 | 2088 | ||
2019 | static int patch_cm9739_specific(ac97_t * ac97) | 2089 | static int patch_cm9739_specific(ac97_t * ac97) |
@@ -2028,7 +2098,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97) | |||
2028 | 2098 | ||
2029 | static struct snd_ac97_build_ops patch_cm9739_ops = { | 2099 | static struct snd_ac97_build_ops patch_cm9739_ops = { |
2030 | .build_specific = patch_cm9739_specific, | 2100 | .build_specific = patch_cm9739_specific, |
2031 | .build_post_spdif = patch_cm9739_post_spdif | 2101 | .build_post_spdif = patch_cm9739_post_spdif, |
2102 | .update_jacks = cm9739_update_jacks | ||
2032 | }; | 2103 | }; |
2033 | 2104 | ||
2034 | int patch_cm9739(ac97_t * ac97) | 2105 | int patch_cm9739(ac97_t * ac97) |
@@ -2090,67 +2161,28 @@ int patch_cm9739(ac97_t * ac97) | |||
2090 | #define AC97_CM9761_FUNC 0x66 | 2161 | #define AC97_CM9761_FUNC 0x66 |
2091 | #define AC97_CM9761_SPDIF_CTRL 0x6c | 2162 | #define AC97_CM9761_SPDIF_CTRL 0x6c |
2092 | 2163 | ||
2093 | static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 2164 | static void cm9761_update_jacks(ac97_t *ac97) |
2094 | { | 2165 | { |
2095 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | 2166 | unsigned short surr_vals[2][2] = { |
2096 | if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x0400) | ||
2097 | ucontrol->value.integer.value[0] = 1; | ||
2098 | else | ||
2099 | ucontrol->value.integer.value[0] = 0; | ||
2100 | return 0; | ||
2101 | } | ||
2102 | |||
2103 | static int snd_ac97_cm9761_linein_rear_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2104 | { | ||
2105 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2106 | unsigned short vals[2][2] = { | ||
2107 | { 0x0008, 0x0400 }, /* off, on */ | 2167 | { 0x0008, 0x0400 }, /* off, on */ |
2108 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ | 2168 | { 0x0000, 0x0408 }, /* off, on (9761-82 rev.B) */ |
2109 | }; | 2169 | }; |
2110 | return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, | 2170 | unsigned short clfe_vals[2][2] = { |
2111 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | ||
2112 | } | ||
2113 | |||
2114 | static int snd_ac97_cm9761_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2115 | { | ||
2116 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2117 | if (ac97->regs[AC97_CM9761_MULTI_CHAN] & 0x1000) | ||
2118 | ucontrol->value.integer.value[0] = 1; | ||
2119 | else | ||
2120 | ucontrol->value.integer.value[0] = 0; | ||
2121 | if (ac97->spec.dev_flags) /* 9761-82 rev.B */ | ||
2122 | ucontrol->value.integer.value[0] = !ucontrol->value.integer.value[0]; | ||
2123 | return 0; | ||
2124 | } | ||
2125 | |||
2126 | static int snd_ac97_cm9761_center_mic_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
2127 | { | ||
2128 | ac97_t *ac97 = snd_kcontrol_chip(kcontrol); | ||
2129 | unsigned short vals[2][2] = { | ||
2130 | { 0x2000, 0x1880 }, /* off, on */ | 2171 | { 0x2000, 0x1880 }, /* off, on */ |
2131 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ | 2172 | { 0x1000, 0x2880 }, /* off, on (9761-82 rev.B) */ |
2132 | }; | 2173 | }; |
2133 | return snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, | 2174 | |
2134 | vals[ac97->spec.dev_flags][!!ucontrol->value.integer.value[0]]); | 2175 | /* shared Line-In */ |
2176 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x0408, | ||
2177 | surr_vals[ac97->spec.dev_flags][is_shared_linein(ac97)]); | ||
2178 | /* shared Mic */ | ||
2179 | snd_ac97_update_bits(ac97, AC97_CM9761_MULTI_CHAN, 0x3880, | ||
2180 | clfe_vals[ac97->spec.dev_flags][is_shared_micin(ac97)]); | ||
2135 | } | 2181 | } |
2136 | 2182 | ||
2137 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { | 2183 | static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { |
2138 | { | 2184 | AC97_SURROUND_JACK_MODE_CTL, |
2139 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2185 | AC97_CHANNEL_MODE_CTL, |
2140 | .name = "Line-In As Surround", | ||
2141 | .info = snd_ac97_info_volsw, | ||
2142 | .get = snd_ac97_cm9761_linein_rear_get, | ||
2143 | .put = snd_ac97_cm9761_linein_rear_put, | ||
2144 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2145 | }, | ||
2146 | { | ||
2147 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2148 | .name = "Mic As Center/LFE", | ||
2149 | .info = snd_ac97_info_volsw, | ||
2150 | .get = snd_ac97_cm9761_center_mic_get, | ||
2151 | .put = snd_ac97_cm9761_center_mic_put, | ||
2152 | .private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */ | ||
2153 | }, | ||
2154 | }; | 2186 | }; |
2155 | 2187 | ||
2156 | static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | 2188 | static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) |
@@ -2224,7 +2256,8 @@ static int patch_cm9761_specific(ac97_t * ac97) | |||
2224 | 2256 | ||
2225 | static struct snd_ac97_build_ops patch_cm9761_ops = { | 2257 | static struct snd_ac97_build_ops patch_cm9761_ops = { |
2226 | .build_specific = patch_cm9761_specific, | 2258 | .build_specific = patch_cm9761_specific, |
2227 | .build_post_spdif = patch_cm9761_post_spdif | 2259 | .build_post_spdif = patch_cm9761_post_spdif, |
2260 | .update_jacks = cm9761_update_jacks | ||
2228 | }; | 2261 | }; |
2229 | 2262 | ||
2230 | int patch_cm9761(ac97_t *ac97) | 2263 | int patch_cm9761(ac97_t *ac97) |
@@ -2370,9 +2403,21 @@ int patch_vt1616(ac97_t * ac97) | |||
2370 | return 0; | 2403 | return 0; |
2371 | } | 2404 | } |
2372 | 2405 | ||
2406 | /* | ||
2407 | */ | ||
2408 | static void it2646_update_jacks(ac97_t *ac97) | ||
2409 | { | ||
2410 | /* shared Line-In */ | ||
2411 | snd_ac97_update_bits(ac97, 0x76, 1 << 9, | ||
2412 | is_shared_linein(ac97) ? (1<<9) : 0); | ||
2413 | /* shared Mic */ | ||
2414 | snd_ac97_update_bits(ac97, 0x76, 1 << 10, | ||
2415 | is_shared_micin(ac97) ? (1<<10) : 0); | ||
2416 | } | ||
2417 | |||
2373 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { | 2418 | static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { |
2374 | AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), | 2419 | AC97_SURROUND_JACK_MODE_CTL, |
2375 | AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), | 2420 | AC97_CHANNEL_MODE_CTL, |
2376 | }; | 2421 | }; |
2377 | 2422 | ||
2378 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { | 2423 | static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { |
@@ -2392,7 +2437,8 @@ static int patch_it2646_specific(ac97_t * ac97) | |||
2392 | } | 2437 | } |
2393 | 2438 | ||
2394 | static struct snd_ac97_build_ops patch_it2646_ops = { | 2439 | static struct snd_ac97_build_ops patch_it2646_ops = { |
2395 | .build_specific = patch_it2646_specific | 2440 | .build_specific = patch_it2646_specific, |
2441 | .update_jacks = it2646_update_jacks | ||
2396 | }; | 2442 | }; |
2397 | 2443 | ||
2398 | int patch_it2646(ac97_t * ac97) | 2444 | int patch_it2646(ac97_t * ac97) |