aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ac97/ac97_patch.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2005-04-13 08:32:57 -0400
committerJaroslav Kysela <perex@suse.cz>2005-05-29 04:00:48 -0400
commiteb8caf30f4c059ddfdfa32b6034549622953db6f (patch)
tree994ff6f1a8b19fb8914af3eae6035fd32b834c0f /sound/pci/ac97/ac97_patch.c
parent267cdf4036ed9e8565a7d909fdf854b9c7e1c5ff (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.c426
1 files changed, 236 insertions, 190 deletions
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 473840d431b..7f16c306165 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 */
70static 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
82static 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
88static 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
96static 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
110static 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
118static 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
126static 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
166static inline int is_shared_linein(ac97_t *ac97)
167{
168 return ! ac97->indep_surround && ac97->channel_mode >= 1;
169}
170
171static 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
1503static 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
1393static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { 1513static 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
1413static int patch_ad1888_specific(ac97_t *ac97) 1538static 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
1429int patch_ad1888(ac97_t * ac97) 1555int 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 */
1524static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) 1650static 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
1531static 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
1551static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { 1671static 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
1583static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { 1697static 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
1603static struct snd_ac97_build_ops patch_alc650_ops = { 1717static 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
1607int patch_alc650(ac97_t * ac97) 1722int 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
1662static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) 1777static 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
1669static 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
1682static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { 1794static 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
1695static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 1800static 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
1761static struct snd_ac97_build_ops patch_alc655_ops = { 1866static 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
1765int patch_alc655(ac97_t * ac97) 1871int 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
1801static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) 1907static 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
1808static 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);
1820static 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
1827static 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
1839static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = { 1929static 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
1860static int patch_alc850_specific(ac97_t *ac97) 1935static int patch_alc850_specific(ac97_t *ac97)
@@ -1871,7 +1946,8 @@ static int patch_alc850_specific(ac97_t *ac97)
1871} 1946}
1872 1947
1873static struct snd_ac97_build_ops patch_alc850_ops = { 1948static 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
1877int patch_alc850(ac97_t *ac97) 1953int 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 */
1990static 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
1914static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { 1997static 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
1919static int patch_cm9738_specific(ac97_t * ac97) 2003static int patch_cm9738_specific(ac97_t * ac97)
@@ -1922,7 +2006,8 @@ static int patch_cm9738_specific(ac97_t * ac97)
1922} 2006}
1923 2007
1924static struct snd_ac97_build_ops patch_cm9738_ops = { 2008static 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
1928int patch_cm9738(ac97_t * ac97) 2013int 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
1989static int snd_ac97_cm9739_center_mic_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2074static 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
1999static 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
2007static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { 2084static 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
2019static int patch_cm9739_specific(ac97_t * ac97) 2089static int patch_cm9739_specific(ac97_t * ac97)
@@ -2028,7 +2098,8 @@ static int patch_cm9739_post_spdif(ac97_t * ac97)
2028 2098
2029static struct snd_ac97_build_ops patch_cm9739_ops = { 2099static 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
2034int patch_cm9739(ac97_t * ac97) 2105int 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
2093static int snd_ac97_cm9761_linein_rear_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2164static 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
2103static 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
2114static 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
2126static 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
2137static const snd_kcontrol_new_t snd_ac97_cm9761_controls[] = { 2183static 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
2156static int cm9761_spdif_out_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 2188static 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
2225static struct snd_ac97_build_ops patch_cm9761_ops = { 2257static 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
2230int patch_cm9761(ac97_t *ac97) 2263int 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 */
2408static 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
2373static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { 2418static 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
2378static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { 2423static 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
2394static struct snd_ac97_build_ops patch_it2646_ops = { 2439static 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
2398int patch_it2646(ac97_t * ac97) 2444int patch_it2646(ac97_t * ac97)