diff options
author | David Woodhouse <dwmw2@infradead.org> | 2008-02-03 02:29:41 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2008-02-03 02:30:32 -0500 |
commit | c1f3ee120bb61045b1c0a3ead620d1d65af47130 (patch) | |
tree | 908430bf2b47fe8e96ac623ae7ab6dd5698d0938 /sound/pci | |
parent | e619a75ff6201b567a539e787aa9af9bc63a3187 (diff) | |
parent | 9135f1901ee6449dfe338adf6e40e9c2025b8150 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'sound/pci')
155 files changed, 14309 insertions, 2782 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 356bf21a1506..812085d521f1 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -183,6 +183,30 @@ config SND_CMIPCI | |||
183 | To compile this driver as a module, choose M here: the module | 183 | To compile this driver as a module, choose M here: the module |
184 | will be called snd-cmipci. | 184 | will be called snd-cmipci. |
185 | 185 | ||
186 | config SND_OXYGEN_LIB | ||
187 | tristate | ||
188 | depends on SND | ||
189 | select SND_PCM | ||
190 | select SND_MPU401_UART | ||
191 | |||
192 | config SND_OXYGEN | ||
193 | tristate "C-Media 8788 (Oxygen)" | ||
194 | depends on SND | ||
195 | select SND_OXYGEN_LIB | ||
196 | help | ||
197 | Say Y here to include support for sound cards based on the | ||
198 | C-Media CMI8788 (Oxygen HD Audio) chip: | ||
199 | * Asound A-8788 | ||
200 | * AuzenTech X-Meridian | ||
201 | * Bgears b-Enspirer | ||
202 | * Club3D Theatron DTS | ||
203 | * HT-Omega Claro | ||
204 | * Razer Barracuda AC-1 | ||
205 | * Sondigo Inferno | ||
206 | |||
207 | To compile this driver as a module, choose M here: the module | ||
208 | will be called snd-oxygen. | ||
209 | |||
186 | config SND_CS4281 | 210 | config SND_CS4281 |
187 | tristate "Cirrus Logic (Sound Fusion) CS4281" | 211 | tristate "Cirrus Logic (Sound Fusion) CS4281" |
188 | depends on SND | 212 | depends on SND |
@@ -623,6 +647,17 @@ config SND_HDSPM | |||
623 | To compile this driver as a module, choose M here: the module | 647 | To compile this driver as a module, choose M here: the module |
624 | will be called snd-hdspm. | 648 | will be called snd-hdspm. |
625 | 649 | ||
650 | config SND_HIFIER | ||
651 | tristate "TempoTec HiFier Fantasia" | ||
652 | depends on SND | ||
653 | select SND_OXYGEN_LIB | ||
654 | help | ||
655 | Say Y here to include support for the MediaTek/TempoTec HiFier | ||
656 | Fantasia sound card. | ||
657 | |||
658 | To compile this driver as a module, choose M here: the module | ||
659 | will be called snd-hifier. | ||
660 | |||
626 | config SND_ICE1712 | 661 | config SND_ICE1712 |
627 | tristate "ICEnsemble ICE1712 (Envy24)" | 662 | tristate "ICEnsemble ICE1712 (Envy24)" |
628 | depends on SND | 663 | depends on SND |
@@ -802,6 +837,16 @@ config SND_RME9652 | |||
802 | To compile this driver as a module, choose M here: the module | 837 | To compile this driver as a module, choose M here: the module |
803 | will be called snd-rme9652. | 838 | will be called snd-rme9652. |
804 | 839 | ||
840 | config SND_SIS7019 | ||
841 | tristate "SiS 7019 Audio Accelerator" | ||
842 | depends on SND && X86 && !X86_64 | ||
843 | select SND_AC97_CODEC | ||
844 | help | ||
845 | Say Y here to include support for the SiS 7019 Audio Accelerator. | ||
846 | |||
847 | To compile this driver as a module, choose M here: the module | ||
848 | will be called snd-sis7019. | ||
849 | |||
805 | config SND_SONICVIBES | 850 | config SND_SONICVIBES |
806 | tristate "S3 SonicVibes" | 851 | tristate "S3 SonicVibes" |
807 | depends on SND | 852 | depends on SND |
@@ -850,6 +895,17 @@ config SND_VIA82XX_MODEM | |||
850 | To compile this driver as a module, choose M here: the module | 895 | To compile this driver as a module, choose M here: the module |
851 | will be called snd-via82xx-modem. | 896 | will be called snd-via82xx-modem. |
852 | 897 | ||
898 | config SND_VIRTUOSO | ||
899 | tristate "Asus Virtuoso 200 (Xonar)" | ||
900 | depends on SND | ||
901 | select SND_OXYGEN_LIB | ||
902 | help | ||
903 | Say Y here to include support for sound cards based on the | ||
904 | Asus AV200 chip, i.e., Xonar D2 and Xonar D2X. | ||
905 | |||
906 | To compile this driver as a module, choose M here: the module | ||
907 | will be called snd-virtuoso. | ||
908 | |||
853 | config SND_VX222 | 909 | config SND_VX222 |
854 | tristate "Digigram VX222" | 910 | tristate "Digigram VX222" |
855 | depends on SND | 911 | depends on SND |
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 09ddc82eeca2..2d42fd28f4e7 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
@@ -23,6 +23,7 @@ snd-intel8x0m-objs := intel8x0m.o | |||
23 | snd-maestro3-objs := maestro3.o | 23 | snd-maestro3-objs := maestro3.o |
24 | snd-rme32-objs := rme32.o | 24 | snd-rme32-objs := rme32.o |
25 | snd-rme96-objs := rme96.o | 25 | snd-rme96-objs := rme96.o |
26 | snd-sis7019-objs := sis7019.o | ||
26 | snd-sonicvibes-objs := sonicvibes.o | 27 | snd-sonicvibes-objs := sonicvibes.o |
27 | snd-via82xx-objs := via82xx.o | 28 | snd-via82xx-objs := via82xx.o |
28 | snd-via82xx-modem-objs := via82xx_modem.o | 29 | snd-via82xx-modem-objs := via82xx_modem.o |
@@ -48,6 +49,7 @@ obj-$(CONFIG_SND_INTEL8X0M) += snd-intel8x0m.o | |||
48 | obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o | 49 | obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o |
49 | obj-$(CONFIG_SND_RME32) += snd-rme32.o | 50 | obj-$(CONFIG_SND_RME32) += snd-rme32.o |
50 | obj-$(CONFIG_SND_RME96) += snd-rme96.o | 51 | obj-$(CONFIG_SND_RME96) += snd-rme96.o |
52 | obj-$(CONFIG_SND_SIS7019) += snd-sis7019.o | ||
51 | obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o | 53 | obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o |
52 | obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o | 54 | obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o |
53 | obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o | 55 | obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o |
@@ -66,6 +68,7 @@ obj-$(CONFIG_SND) += \ | |||
66 | korg1212/ \ | 68 | korg1212/ \ |
67 | mixart/ \ | 69 | mixart/ \ |
68 | nm256/ \ | 70 | nm256/ \ |
71 | oxygen/ \ | ||
69 | pcxhr/ \ | 72 | pcxhr/ \ |
70 | riptide/ \ | 73 | riptide/ \ |
71 | rme9652/ \ | 74 | rme9652/ \ |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 6a9966df0cc9..45fd29017ddd 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 98c8b727b62b..50c637e55ffa 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -133,6 +133,14 @@ static int ac97_channel_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
133 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 133 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
134 | unsigned char mode = ucontrol->value.enumerated.item[0]; | 134 | unsigned char mode = ucontrol->value.enumerated.item[0]; |
135 | 135 | ||
136 | if (kcontrol->private_value) { | ||
137 | if (mode >= 2) | ||
138 | return -EINVAL; | ||
139 | } else { | ||
140 | if (mode >= 3) | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
136 | if (mode != ac97->channel_mode) { | 144 | if (mode != ac97->channel_mode) { |
137 | ac97->channel_mode = mode; | 145 | ac97->channel_mode = mode; |
138 | if (ac97->build_ops->update_jacks) | 146 | if (ac97->build_ops->update_jacks) |
@@ -2142,8 +2150,7 @@ static int snd_ac97_ad1985_vrefout_put(struct snd_kcontrol *kcontrol, | |||
2142 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); | 2150 | struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol); |
2143 | unsigned short val; | 2151 | unsigned short val; |
2144 | 2152 | ||
2145 | if (ucontrol->value.enumerated.item[0] > 3 | 2153 | if (ucontrol->value.enumerated.item[0] > 3) |
2146 | || ucontrol->value.enumerated.item[0] < 0) | ||
2147 | return -EINVAL; | 2154 | return -EINVAL; |
2148 | val = ctrl2reg[ucontrol->value.enumerated.item[0]] | 2155 | val = ctrl2reg[ucontrol->value.enumerated.item[0]] |
2149 | << AC97_AD198X_VREF_SHIFT; | 2156 | << AC97_AD198X_VREF_SHIFT; |
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h index 9cccc27ea1b5..47bf8dfe8276 100644 --- a/sound/pci/ac97/ac97_patch.h +++ b/sound/pci/ac97/ac97_patch.h | |||
@@ -83,8 +83,10 @@ static int snd_ac97_swap_ctl(struct snd_ac97 *ac97, const char *s1, | |||
83 | const char *s2, const char *suffix); | 83 | const char *s2, const char *suffix); |
84 | static void snd_ac97_rename_vol_ctl(struct snd_ac97 *ac97, const char *src, | 84 | static void snd_ac97_rename_vol_ctl(struct snd_ac97 *ac97, const char *src, |
85 | const char *dst); | 85 | const char *dst); |
86 | #ifdef CONFIG_PM | ||
86 | static void snd_ac97_restore_status(struct snd_ac97 *ac97); | 87 | static void snd_ac97_restore_status(struct snd_ac97 *ac97); |
87 | static void snd_ac97_restore_iec958(struct snd_ac97 *ac97); | 88 | static void snd_ac97_restore_iec958(struct snd_ac97 *ac97); |
89 | #endif | ||
88 | static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol, | 90 | static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol, |
89 | struct snd_ctl_elem_info *uinfo); | 91 | struct snd_ctl_elem_info *uinfo); |
90 | static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol, | 92 | static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol, |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index 8cbc03332b01..3674f35c4a79 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index fed4a2c3d8a1..060ea59d5f02 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
27 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
28 | 27 | ||
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 722de451d15f..c0c1633999ea 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 98970d401be9..a66d5150bb7a 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include <linux/compiler.h> | 40 | #include <linux/compiler.h> |
41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <sound/core.h> | 43 | #include <sound/core.h> |
45 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
46 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
@@ -1055,7 +1054,7 @@ static struct pci_device_id snd_ad1889_ids[] = { | |||
1055 | }; | 1054 | }; |
1056 | MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); | 1055 | MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); |
1057 | 1056 | ||
1058 | static struct pci_driver ad1889_pci = { | 1057 | static struct pci_driver ad1889_pci_driver = { |
1059 | .name = "AD1889 Audio", | 1058 | .name = "AD1889 Audio", |
1060 | .id_table = snd_ad1889_ids, | 1059 | .id_table = snd_ad1889_ids, |
1061 | .probe = snd_ad1889_probe, | 1060 | .probe = snd_ad1889_probe, |
@@ -1065,13 +1064,13 @@ static struct pci_driver ad1889_pci = { | |||
1065 | static int __init | 1064 | static int __init |
1066 | alsa_ad1889_init(void) | 1065 | alsa_ad1889_init(void) |
1067 | { | 1066 | { |
1068 | return pci_register_driver(&ad1889_pci); | 1067 | return pci_register_driver(&ad1889_pci_driver); |
1069 | } | 1068 | } |
1070 | 1069 | ||
1071 | static void __exit | 1070 | static void __exit |
1072 | alsa_ad1889_fini(void) | 1071 | alsa_ad1889_fini(void) |
1073 | { | 1072 | { |
1074 | pci_unregister_driver(&ad1889_pci); | 1073 | pci_unregister_driver(&ad1889_pci_driver); |
1075 | } | 1074 | } |
1076 | 1075 | ||
1077 | module_init(alsa_ad1889_init); | 1076 | module_init(alsa_ad1889_init); |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 4c2bd7adf674..6a905ed9cbd6 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <asm/io.h> | 28 | #include <asm/io.h> |
30 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 48cc39b771d9..0e990a735821 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * to keep track of what period we are in. | 30 | * to keep track of what period we are in. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
36 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 1190ef366a41..27ce6136ab00 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -63,7 +63,6 @@ | |||
63 | * - power management? (card can do voice wakeup according to datasheet!!) | 63 | * - power management? (card can do voice wakeup according to datasheet!!) |
64 | */ | 64 | */ |
65 | 65 | ||
66 | #include <sound/driver.h> | ||
67 | #include <asm/io.h> | 66 | #include <asm/io.h> |
68 | #include <linux/init.h> | 67 | #include <linux/init.h> |
69 | #include <linux/pci.h> | 68 | #include <linux/pci.h> |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 89184a424140..4594186b83ee 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
@@ -560,7 +559,7 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) | |||
560 | ATI_REG_ISR_CODEC2_NOT_READY) | 559 | ATI_REG_ISR_CODEC2_NOT_READY) |
561 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) | 560 | #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) |
562 | 561 | ||
563 | static int ac97_probing_bugs(struct pci_dev *pci) | 562 | static int __devinit ac97_probing_bugs(struct pci_dev *pci) |
564 | { | 563 | { |
565 | const struct snd_pci_quirk *q; | 564 | const struct snd_pci_quirk *q; |
566 | 565 | ||
@@ -574,7 +573,7 @@ static int ac97_probing_bugs(struct pci_dev *pci) | |||
574 | return -1; | 573 | return -1; |
575 | } | 574 | } |
576 | 575 | ||
577 | static int snd_atiixp_codec_detect(struct atiixp *chip) | 576 | static int __devinit snd_atiixp_codec_detect(struct atiixp *chip) |
578 | { | 577 | { |
579 | int timeout; | 578 | int timeout; |
580 | 579 | ||
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index ce752f84457a..a67a869180d4 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index 5ccf0b1ec670..4aad35bba11a 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h | |||
@@ -18,7 +18,6 @@ | |||
18 | #define __SOUND_AU88X0_H | 18 | #define __SOUND_AU88X0_H |
19 | 19 | ||
20 | #ifdef __KERNEL__ | 20 | #ifdef __KERNEL__ |
21 | #include <sound/driver.h> | ||
22 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 4a336eaae9d2..333c62de8620 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c | |||
@@ -2395,7 +2395,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) | |||
2395 | if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1)) | 2395 | if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1)) |
2396 | return IRQ_NONE; | 2396 | return IRQ_NONE; |
2397 | 2397 | ||
2398 | // This is the Interrrupt Enable flag we set before (consistency check). | 2398 | // This is the Interrupt Enable flag we set before (consistency check). |
2399 | if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE)) | 2399 | if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE)) |
2400 | return IRQ_NONE; | 2400 | return IRQ_NONE; |
2401 | 2401 | ||
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index a07d1deba322..bc212f41a38a 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * driver. (email: mjander@embedded.cl). | 30 | * driver. (email: mjander@embedded.cl). |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/time.h> | 33 | #include <linux/time.h> |
35 | #include <linux/delay.h> | 34 | #include <linux/delay.h> |
36 | #include <linux/init.h> | 35 | #include <linux/init.h> |
diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index c96da1dab863..c92f493d341e 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <sound/driver.h> | ||
9 | #include <linux/time.h> | 8 | #include <linux/time.h> |
10 | #include <linux/init.h> | 9 | #include <linux/init.h> |
11 | #include <sound/core.h> | 10 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 8db3d3e6f7bb..0dc8d259d1ed 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <sound/core.h> | 26 | #include <sound/core.h> |
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 7b5baa173859..526c6c5ecf7b 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * It remains stuck,and DMA transfers do not happen. | 21 | * It remains stuck,and DMA transfers do not happen. |
22 | */ | 22 | */ |
23 | #include <sound/asoundef.h> | 23 | #include <sound/asoundef.h> |
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 36d3666a5b77..4e71a55120a0 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -115,7 +115,6 @@ | |||
115 | * code (but I'm not too optimistic that doing this is possible at all) | 115 | * code (but I'm not too optimistic that doing this is possible at all) |
116 | */ | 116 | */ |
117 | 117 | ||
118 | #include <sound/driver.h> | ||
119 | #include <asm/io.h> | 118 | #include <asm/io.h> |
120 | #include <linux/init.h> | 119 | #include <linux/init.h> |
121 | #include <linux/pci.h> | 120 | #include <linux/pci.h> |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 2dba752faf4e..c9a2421cf6f0 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index 75da1746e758..74175fc80c7f 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -272,7 +272,6 @@ | |||
272 | #define SPCS_WORD_LENGTH_20A 0x0000000a /* Word Length 20 bit */ | 272 | #define SPCS_WORD_LENGTH_20A 0x0000000a /* Word Length 20 bit */ |
273 | #define SPCS_WORD_LENGTH_20 0x00000009 /* Word Length 20 bit (both 0xa and 0x9 are 20 bit) */ | 273 | #define SPCS_WORD_LENGTH_20 0x00000009 /* Word Length 20 bit (both 0xa and 0x9 are 20 bit) */ |
274 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ | 274 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ |
275 | #define SPCS_WORD_LENGTH_21 0x00000007 /* Word Length 21 bit */ | ||
276 | #define SPCS_WORD_LENGTH_22 0x00000005 /* Word Length 22 bit */ | 275 | #define SPCS_WORD_LENGTH_22 0x00000005 /* Word Length 22 bit */ |
277 | #define SPCS_WORD_LENGTH_23 0x00000003 /* Word Length 23 bit */ | 276 | #define SPCS_WORD_LENGTH_23 0x00000003 /* Word Length 23 bit */ |
278 | #define SPCS_WORD_LENGTH_24 0x0000000b /* Word Length 24 bit */ | 277 | #define SPCS_WORD_LENGTH_24 0x0000000b /* Word Length 24 bit */ |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 31d8db9f7a4c..176e0f0e8058 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -135,7 +135,6 @@ | |||
135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 135 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
136 | * | 136 | * |
137 | */ | 137 | */ |
138 | #include <sound/driver.h> | ||
139 | #include <linux/delay.h> | 138 | #include <linux/delay.h> |
140 | #include <linux/init.h> | 139 | #include <linux/init.h> |
141 | #include <linux/interrupt.h> | 140 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index be519a17dfa5..af736869d9b1 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -60,7 +60,6 @@ | |||
60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
61 | * | 61 | * |
62 | */ | 62 | */ |
63 | #include <sound/driver.h> | ||
64 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
65 | #include <linux/init.h> | 64 | #include <linux/init.h> |
66 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
@@ -86,7 +85,7 @@ static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, | |||
86 | { | 85 | { |
87 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | 86 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); |
88 | 87 | ||
89 | ucontrol->value.enumerated.item[0] = emu->spdif_enable; | 88 | ucontrol->value.integer.value[0] = emu->spdif_enable; |
90 | return 0; | 89 | return 0; |
91 | } | 90 | } |
92 | 91 | ||
@@ -98,11 +97,11 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
98 | int change = 0; | 97 | int change = 0; |
99 | u32 mask; | 98 | u32 mask; |
100 | 99 | ||
101 | val = ucontrol->value.enumerated.item[0] ; | 100 | val = !!ucontrol->value.integer.value[0]; |
102 | change = (emu->spdif_enable != val); | 101 | change = (emu->spdif_enable != val); |
103 | if (change) { | 102 | if (change) { |
104 | emu->spdif_enable = val; | 103 | emu->spdif_enable = val; |
105 | if (val == 1) { | 104 | if (val) { |
106 | /* Digital */ | 105 | /* Digital */ |
107 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); | 106 | snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); |
108 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); | 107 | snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); |
@@ -159,6 +158,8 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, | |||
159 | u32 source; | 158 | u32 source; |
160 | 159 | ||
161 | val = ucontrol->value.enumerated.item[0] ; | 160 | val = ucontrol->value.enumerated.item[0] ; |
161 | if (val >= 6) | ||
162 | return -EINVAL; | ||
162 | change = (emu->capture_source != val); | 163 | change = (emu->capture_source != val); |
163 | if (change) { | 164 | if (change) { |
164 | emu->capture_source = val; | 165 | emu->capture_source = val; |
@@ -207,6 +208,8 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | |||
207 | * for the particular source. | 208 | * for the particular source. |
208 | */ | 209 | */ |
209 | source_id = ucontrol->value.enumerated.item[0] ; | 210 | source_id = ucontrol->value.enumerated.item[0] ; |
211 | if (source_id >= 4) | ||
212 | return -EINVAL; | ||
210 | change = (emu->i2c_capture_source != source_id); | 213 | change = (emu->i2c_capture_source != source_id); |
211 | if (change) { | 214 | if (change) { |
212 | snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | 215 | snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ |
@@ -271,6 +274,8 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
271 | u32 tmp; | 274 | u32 tmp; |
272 | 275 | ||
273 | val = ucontrol->value.enumerated.item[0] ; | 276 | val = ucontrol->value.enumerated.item[0] ; |
277 | if (val > 1) | ||
278 | return -EINVAL; | ||
274 | change = (emu->capture_mic_line_in != val); | 279 | change = (emu->capture_mic_line_in != val); |
275 | if (change) { | 280 | if (change) { |
276 | emu->capture_mic_line_in = val; | 281 | emu->capture_mic_line_in = val; |
@@ -443,7 +448,7 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
443 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | 448 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ |
444 | ngain = ucontrol->value.integer.value[0]; | 449 | ngain = ucontrol->value.integer.value[0]; |
445 | if (ngain > 0xff) | 450 | if (ngain > 0xff) |
446 | return 0; | 451 | return -EINVAL; |
447 | if (ogain != ngain) { | 452 | if (ogain != ngain) { |
448 | if (emu->i2c_capture_source == source_id) | 453 | if (emu->i2c_capture_source == source_id) |
449 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | 454 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); |
@@ -453,7 +458,7 @@ static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
453 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | 458 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ |
454 | ngain = ucontrol->value.integer.value[1]; | 459 | ngain = ucontrol->value.integer.value[1]; |
455 | if (ngain > 0xff) | 460 | if (ngain > 0xff) |
456 | return 0; | 461 | return -EINVAL; |
457 | if (ogain != ngain) { | 462 | if (ogain != ngain) { |
458 | if (emu->i2c_capture_source == source_id) | 463 | if (emu->i2c_capture_source == source_id) |
459 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | 464 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); |
@@ -497,7 +502,7 @@ static int spi_mute_put(struct snd_kcontrol *kcontrol, | |||
497 | } | 502 | } |
498 | 503 | ||
499 | ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); | 504 | ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); |
500 | return ret ? -1 : 1; | 505 | return ret ? -EINVAL : 1; |
501 | } | 506 | } |
502 | 507 | ||
503 | #define CA_VOLUME(xname,chid,reg) \ | 508 | #define CA_VOLUME(xname,chid,reg) \ |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index ae80f51d8c4f..c62b7d10ec61 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
@@ -60,7 +60,6 @@ | |||
60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 60 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
61 | * | 61 | * |
62 | */ | 62 | */ |
63 | #include <sound/driver.h> | ||
64 | #include <linux/delay.h> | 63 | #include <linux/delay.h> |
65 | #include <linux/init.h> | 64 | #include <linux/init.h> |
66 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
@@ -445,13 +444,11 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu) | |||
445 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); | 444 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); |
446 | entry->c.text.write = snd_ca0106_proc_reg_write; | 445 | entry->c.text.write = snd_ca0106_proc_reg_write; |
447 | entry->mode |= S_IWUSR; | 446 | entry->mode |= S_IWUSR; |
448 | // entry->private_data = emu; | ||
449 | } | 447 | } |
450 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { | 448 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { |
451 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write); | ||
452 | entry->c.text.write = snd_ca0106_proc_i2c_write; | 449 | entry->c.text.write = snd_ca0106_proc_i2c_write; |
450 | entry->private_data = emu; | ||
453 | entry->mode |= S_IWUSR; | 451 | entry->mode |= S_IWUSR; |
454 | // entry->private_data = emu; | ||
455 | } | 452 | } |
456 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) | 453 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) |
457 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); | 454 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); |
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index ad32eff2713f..893ee4f1ea77 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c | |||
@@ -27,7 +27,6 @@ | |||
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <sound/driver.h> | ||
31 | #include <sound/core.h> | 30 | #include <sound/core.h> |
32 | #include <sound/rawmidi.h> | 31 | #include <sound/rawmidi.h> |
33 | 32 | ||
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 6832649879ce..135f30860753 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -20,7 +20,6 @@ | |||
20 | /* Does not work. Warning may block system in capture mode */ | 20 | /* Does not work. Warning may block system in capture mode */ |
21 | /* #define USE_VAR48KRATE */ | 21 | /* #define USE_VAR48KRATE */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -150,6 +149,8 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); | |||
150 | #define CM_CH0_SRATE_176K 0x00000200 | 149 | #define CM_CH0_SRATE_176K 0x00000200 |
151 | #define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ | 150 | #define CM_CH0_SRATE_96K 0x00000200 /* model 055? */ |
152 | #define CM_CH0_SRATE_88K 0x00000100 | 151 | #define CM_CH0_SRATE_88K 0x00000100 |
152 | #define CM_CH0_SRATE_128K 0x00000300 | ||
153 | #define CM_CH0_SRATE_MASK 0x00000300 | ||
153 | 154 | ||
154 | #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ | 155 | #define CM_SPDIF_INVERSE2 0x00000080 /* model 055? */ |
155 | #define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ | 156 | #define CM_DBLSPDS 0x00000040 /* double SPDIF sample rate 88.2/96 */ |
@@ -246,10 +247,9 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); | |||
246 | #define CM_MMODE_MASK 0x00000E00 /* model DAA interface mode */ | 247 | #define CM_MMODE_MASK 0x00000E00 /* model DAA interface mode */ |
247 | #define CM_SPDIF_SELECT2 0x00000100 /* for model > 039 ? */ | 248 | #define CM_SPDIF_SELECT2 0x00000100 /* for model > 039 ? */ |
248 | #define CM_ENCENTER 0x00000080 | 249 | #define CM_ENCENTER 0x00000080 |
249 | #define CM_FLINKON 0x00000080 /* force modem link detection on, model 037 */ | 250 | #define CM_FLINKON 0x00000040 /* force modem link detection on, model 037 */ |
250 | #define CM_MUTECH1 0x00000040 /* mute PCI ch1 to DAC */ | 251 | #define CM_MUTECH1 0x00000040 /* mute PCI ch1 to DAC */ |
251 | #define CM_FLINKOFF 0x00000040 /* force modem link detection off, model 037 */ | 252 | #define CM_FLINKOFF 0x00000020 /* force modem link detection off, model 037 */ |
252 | #define CM_UNKNOWN_18_5 0x00000020 /* ? */ | ||
253 | #define CM_MIDSMP 0x00000010 /* 1/2 interpolation at front end DAC */ | 253 | #define CM_MIDSMP 0x00000010 /* 1/2 interpolation at front end DAC */ |
254 | #define CM_UPDDMA_MASK 0x0000000C /* TDMA position update notification */ | 254 | #define CM_UPDDMA_MASK 0x0000000C /* TDMA position update notification */ |
255 | #define CM_UPDDMA_2048 0x00000000 | 255 | #define CM_UPDDMA_2048 0x00000000 |
@@ -474,6 +474,7 @@ struct cmipci { | |||
474 | unsigned int can_ac3_sw: 1; | 474 | unsigned int can_ac3_sw: 1; |
475 | unsigned int can_ac3_hw: 1; | 475 | unsigned int can_ac3_hw: 1; |
476 | unsigned int can_multi_ch: 1; | 476 | unsigned int can_multi_ch: 1; |
477 | unsigned int can_96k: 1; /* samplerate above 48k */ | ||
477 | unsigned int do_soft_ac3: 1; | 478 | unsigned int do_soft_ac3: 1; |
478 | 479 | ||
479 | unsigned int spdif_playback_avail: 1; /* spdif ready? */ | 480 | unsigned int spdif_playback_avail: 1; /* spdif ready? */ |
@@ -604,8 +605,6 @@ static unsigned int snd_cmipci_rate_freq(unsigned int rate) | |||
604 | { | 605 | { |
605 | unsigned int i; | 606 | unsigned int i; |
606 | 607 | ||
607 | if (rate > 48000) | ||
608 | rate /= 2; | ||
609 | for (i = 0; i < ARRAY_SIZE(rates); i++) { | 608 | for (i = 0; i < ARRAY_SIZE(rates); i++) { |
610 | if (rates[i] == rate) | 609 | if (rates[i] == rate) |
611 | return i; | 610 | return i; |
@@ -783,7 +782,7 @@ static int set_dac_channels(struct cmipci *cm, struct cmipci_pcm *rec, int chann | |||
783 | static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | 782 | static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, |
784 | struct snd_pcm_substream *substream) | 783 | struct snd_pcm_substream *substream) |
785 | { | 784 | { |
786 | unsigned int reg, freq, val; | 785 | unsigned int reg, freq, freq_ext, val; |
787 | unsigned int period_size; | 786 | unsigned int period_size; |
788 | struct snd_pcm_runtime *runtime = substream->runtime; | 787 | struct snd_pcm_runtime *runtime = substream->runtime; |
789 | 788 | ||
@@ -831,7 +830,17 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | |||
831 | //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); | 830 | //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); |
832 | 831 | ||
833 | /* set sample rate */ | 832 | /* set sample rate */ |
834 | freq = snd_cmipci_rate_freq(runtime->rate); | 833 | freq = 0; |
834 | freq_ext = 0; | ||
835 | if (runtime->rate > 48000) | ||
836 | switch (runtime->rate) { | ||
837 | case 88200: freq_ext = CM_CH0_SRATE_88K; break; | ||
838 | case 96000: freq_ext = CM_CH0_SRATE_96K; break; | ||
839 | case 128000: freq_ext = CM_CH0_SRATE_128K; break; | ||
840 | default: snd_BUG(); break; | ||
841 | } | ||
842 | else | ||
843 | freq = snd_cmipci_rate_freq(runtime->rate); | ||
835 | val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); | 844 | val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); |
836 | if (rec->ch) { | 845 | if (rec->ch) { |
837 | val &= ~CM_DSFC_MASK; | 846 | val &= ~CM_DSFC_MASK; |
@@ -852,19 +861,20 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, | |||
852 | val &= ~CM_CH0FMT_MASK; | 861 | val &= ~CM_CH0FMT_MASK; |
853 | val |= rec->fmt << CM_CH0FMT_SHIFT; | 862 | val |= rec->fmt << CM_CH0FMT_SHIFT; |
854 | } | 863 | } |
855 | if (cm->chip_version == 68) { | 864 | if (cm->can_96k) { |
856 | if (runtime->rate == 88200) | 865 | val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); |
857 | val |= CM_CH0_SRATE_88K << (rec->ch * 2); | 866 | val |= freq_ext << (rec->ch * 2); |
858 | else | ||
859 | val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | ||
860 | if (runtime->rate == 96000) | ||
861 | val |= CM_CH0_SRATE_96K << (rec->ch * 2); | ||
862 | else | ||
863 | val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | ||
864 | } | 867 | } |
865 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | 868 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); |
866 | //snd_printd("cmipci: chformat = %08x\n", val); | 869 | //snd_printd("cmipci: chformat = %08x\n", val); |
867 | 870 | ||
871 | if (!rec->is_dac && cm->chip_version) { | ||
872 | if (runtime->rate > 44100) | ||
873 | snd_cmipci_set_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K); | ||
874 | else | ||
875 | snd_cmipci_clear_bit(cm, CM_REG_EXT_MISC, CM_ADC48K44K); | ||
876 | } | ||
877 | |||
868 | rec->running = 0; | 878 | rec->running = 0; |
869 | spin_unlock_irq(&cm->reg_lock); | 879 | spin_unlock_irq(&cm->reg_lock); |
870 | 880 | ||
@@ -1281,7 +1291,7 @@ static int snd_cmipci_playback_prepare(struct snd_pcm_substream *substream) | |||
1281 | int rate = substream->runtime->rate; | 1291 | int rate = substream->runtime->rate; |
1282 | int err, do_spdif, do_ac3 = 0; | 1292 | int err, do_spdif, do_ac3 = 0; |
1283 | 1293 | ||
1284 | do_spdif = (rate >= 44100 && | 1294 | do_spdif = (rate >= 44100 && rate <= 96000 && |
1285 | substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && | 1295 | substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE && |
1286 | substream->runtime->channels == 2); | 1296 | substream->runtime->channels == 2); |
1287 | if (do_spdif && cm->can_ac3_hw) | 1297 | if (do_spdif && cm->can_ac3_hw) |
@@ -1337,10 +1347,8 @@ static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) | |||
1337 | val = snd_cmipci_read(cm, CM_REG_CHFORMAT); | 1347 | val = snd_cmipci_read(cm, CM_REG_CHFORMAT); |
1338 | val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); | 1348 | val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); |
1339 | val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); | 1349 | val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); |
1340 | if (cm->chip_version == 68) { | 1350 | if (cm->can_96k) |
1341 | val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | 1351 | val &= ~(CM_CH0_SRATE_MASK << (rec->ch * 2)); |
1342 | val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | ||
1343 | } | ||
1344 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | 1352 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); |
1345 | 1353 | ||
1346 | /* start stream (we don't need interrupts) */ | 1354 | /* start stream (we don't need interrupts) */ |
@@ -1392,6 +1400,17 @@ static int snd_cmipci_capture_spdif_prepare(struct snd_pcm_substream *substream) | |||
1392 | 1400 | ||
1393 | spin_lock_irq(&cm->reg_lock); | 1401 | spin_lock_irq(&cm->reg_lock); |
1394 | snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); | 1402 | snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); |
1403 | if (cm->can_96k) { | ||
1404 | if (substream->runtime->rate > 48000) | ||
1405 | snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); | ||
1406 | else | ||
1407 | snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_DBLSPDS); | ||
1408 | } | ||
1409 | if (snd_pcm_format_width(substream->runtime->format) > 16) | ||
1410 | snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1411 | else | ||
1412 | snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1413 | |||
1395 | spin_unlock_irq(&cm->reg_lock); | 1414 | spin_unlock_irq(&cm->reg_lock); |
1396 | 1415 | ||
1397 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream); | 1416 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_CAPT], substream); |
@@ -1403,6 +1422,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs) | |||
1403 | 1422 | ||
1404 | spin_lock_irq(&cm->reg_lock); | 1423 | spin_lock_irq(&cm->reg_lock); |
1405 | snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); | 1424 | snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_CAPTURE_SPDF); |
1425 | snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); | ||
1406 | spin_unlock_irq(&cm->reg_lock); | 1426 | spin_unlock_irq(&cm->reg_lock); |
1407 | 1427 | ||
1408 | return snd_cmipci_hw_free(subs); | 1428 | return snd_cmipci_hw_free(subs); |
@@ -1554,7 +1574,8 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = | |||
1554 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 1574 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1555 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | | 1575 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | |
1556 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), | 1576 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
1557 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 1577 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
1578 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | ||
1558 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | 1579 | .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, |
1559 | .rate_min = 44100, | 1580 | .rate_min = 44100, |
1560 | .rate_max = 48000, | 1581 | .rate_max = 48000, |
@@ -1568,6 +1589,14 @@ static struct snd_pcm_hardware snd_cmipci_capture_spdif = | |||
1568 | .fifo_size = 0, | 1589 | .fifo_size = 0, |
1569 | }; | 1590 | }; |
1570 | 1591 | ||
1592 | static unsigned int rate_constraints[] = { 5512, 8000, 11025, 16000, 22050, | ||
1593 | 32000, 44100, 48000, 88200, 96000, 128000 }; | ||
1594 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | ||
1595 | .count = ARRAY_SIZE(rate_constraints), | ||
1596 | .list = rate_constraints, | ||
1597 | .mask = 0, | ||
1598 | }; | ||
1599 | |||
1571 | /* | 1600 | /* |
1572 | * check device open/close | 1601 | * check device open/close |
1573 | */ | 1602 | */ |
@@ -1637,6 +1666,13 @@ static int snd_cmipci_playback_open(struct snd_pcm_substream *substream) | |||
1637 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1666 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1638 | SNDRV_PCM_RATE_96000; | 1667 | SNDRV_PCM_RATE_96000; |
1639 | runtime->hw.rate_max = 96000; | 1668 | runtime->hw.rate_max = 96000; |
1669 | } else if (cm->chip_version == 55) { | ||
1670 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1671 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1672 | if (err < 0) | ||
1673 | return err; | ||
1674 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1675 | runtime->hw.rate_max = 128000; | ||
1640 | } | 1676 | } |
1641 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1677 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1642 | cm->dig_pcm_status = cm->dig_status; | 1678 | cm->dig_pcm_status = cm->dig_status; |
@@ -1655,6 +1691,13 @@ static int snd_cmipci_capture_open(struct snd_pcm_substream *substream) | |||
1655 | if (cm->chip_version == 68) { // 8768 only supports 44k/48k recording | 1691 | if (cm->chip_version == 68) { // 8768 only supports 44k/48k recording |
1656 | runtime->hw.rate_min = 41000; | 1692 | runtime->hw.rate_min = 41000; |
1657 | runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; | 1693 | runtime->hw.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000; |
1694 | } else if (cm->chip_version == 55) { | ||
1695 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1696 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1697 | if (err < 0) | ||
1698 | return err; | ||
1699 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1700 | runtime->hw.rate_max = 128000; | ||
1658 | } | 1701 | } |
1659 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1702 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1660 | return 0; | 1703 | return 0; |
@@ -1686,6 +1729,13 @@ static int snd_cmipci_playback2_open(struct snd_pcm_substream *substream) | |||
1686 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1729 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1687 | SNDRV_PCM_RATE_96000; | 1730 | SNDRV_PCM_RATE_96000; |
1688 | runtime->hw.rate_max = 96000; | 1731 | runtime->hw.rate_max = 96000; |
1732 | } else if (cm->chip_version == 55) { | ||
1733 | err = snd_pcm_hw_constraint_list(runtime, 0, | ||
1734 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
1735 | if (err < 0) | ||
1736 | return err; | ||
1737 | runtime->hw.rates |= SNDRV_PCM_RATE_KNOT; | ||
1738 | runtime->hw.rate_max = 128000; | ||
1689 | } | 1739 | } |
1690 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); | 1740 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); |
1691 | return 0; | 1741 | return 0; |
@@ -1705,7 +1755,7 @@ static int snd_cmipci_playback_spdif_open(struct snd_pcm_substream *substream) | |||
1705 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; | 1755 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; |
1706 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1756 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
1707 | } | 1757 | } |
1708 | if (cm->chip_version == 68) { | 1758 | if (cm->can_96k) { |
1709 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | 1759 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | |
1710 | SNDRV_PCM_RATE_96000; | 1760 | SNDRV_PCM_RATE_96000; |
1711 | runtime->hw.rate_max = 96000; | 1761 | runtime->hw.rate_max = 96000; |
@@ -1727,6 +1777,11 @@ static int snd_cmipci_capture_spdif_open(struct snd_pcm_substream *substream) | |||
1727 | if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ | 1777 | if ((err = open_device_check(cm, CM_OPEN_SPDIF_CAPTURE, substream)) < 0) /* use channel B */ |
1728 | return err; | 1778 | return err; |
1729 | runtime->hw = snd_cmipci_capture_spdif; | 1779 | runtime->hw = snd_cmipci_capture_spdif; |
1780 | if (cm->can_96k && !(cm->chip_version == 68)) { | ||
1781 | runtime->hw.rates |= SNDRV_PCM_RATE_88200 | | ||
1782 | SNDRV_PCM_RATE_96000; | ||
1783 | runtime->hw.rate_max = 96000; | ||
1784 | } | ||
1730 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); | 1785 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); |
1731 | return 0; | 1786 | return 0; |
1732 | } | 1787 | } |
@@ -2595,10 +2650,8 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = | |||
2595 | }; | 2650 | }; |
2596 | 2651 | ||
2597 | /* card control switches */ | 2652 | /* card control switches */ |
2598 | static struct snd_kcontrol_new snd_cmipci_control_switches[] __devinitdata = { | 2653 | static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata = |
2599 | // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */ | 2654 | DEFINE_CARD_SWITCH("Modem", modem); |
2600 | DEFINE_CARD_SWITCH("Modem", modem), | ||
2601 | }; | ||
2602 | 2655 | ||
2603 | 2656 | ||
2604 | static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) | 2657 | static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) |
@@ -2679,9 +2732,13 @@ static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_devic | |||
2679 | } | 2732 | } |
2680 | 2733 | ||
2681 | /* card switches */ | 2734 | /* card switches */ |
2682 | sw = snd_cmipci_control_switches; | 2735 | /* |
2683 | for (idx = 0; idx < ARRAY_SIZE(snd_cmipci_control_switches); idx++, sw++) { | 2736 | * newer chips don't have the register bits to force modem link |
2684 | err = snd_ctl_add(cm->card, snd_ctl_new1(sw, cm)); | 2737 | * detection; the bit that was FLINKON now mutes CH1 |
2738 | */ | ||
2739 | if (cm->chip_version < 39) { | ||
2740 | err = snd_ctl_add(cm->card, | ||
2741 | snd_ctl_new1(&snd_cmipci_modem_switch, cm)); | ||
2685 | if (err < 0) | 2742 | if (err < 0) |
2686 | return err; | 2743 | return err; |
2687 | } | 2744 | } |
@@ -2786,9 +2843,11 @@ static void __devinit query_chip(struct cmipci *cm) | |||
2786 | } else if (detect & CM_CHIP_8768) { | 2843 | } else if (detect & CM_CHIP_8768) { |
2787 | cm->chip_version = 68; | 2844 | cm->chip_version = 68; |
2788 | cm->max_channels = 8; | 2845 | cm->max_channels = 8; |
2846 | cm->can_96k = 1; | ||
2789 | } else { | 2847 | } else { |
2790 | cm->chip_version = 55; | 2848 | cm->chip_version = 55; |
2791 | cm->max_channels = 6; | 2849 | cm->max_channels = 6; |
2850 | cm->can_96k = 1; | ||
2792 | } | 2851 | } |
2793 | cm->can_ac3_hw = 1; | 2852 | cm->can_ac3_hw = 1; |
2794 | cm->can_multi_ch = 1; | 2853 | cm->can_multi_ch = 1; |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9a55f4a9739b..7556fd90d0eb 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | 22 | #include <asm/io.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 2699cb6c2cd6..e876b3263e46 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
@@ -25,7 +25,6 @@ | |||
25 | reloading the module may solve this. | 25 | reloading the module may solve this. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
30 | #include <linux/time.h> | 29 | #include <linux/time.h> |
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 2c7bfc9fef61..87ddffcd9d89 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * - Sometimes the SPDIF input DSP tasks get's unsynchronized | 8 | * - Sometimes the SPDIF input DSP tasks get's unsynchronized |
9 | * and the SPDIF get somewhat "distorcionated", or/and left right channel | 9 | * and the SPDIF get somewhat "distorcionated", or/and left right channel |
10 | * are swapped. To get around this problem when it happens, mute and unmute | 10 | * are swapped. To get around this problem when it happens, mute and unmute |
11 | * the SPDIF input mixer controll. | 11 | * the SPDIF input mixer control. |
12 | * - On the Hercules Game Theater XP the amplifier are sometimes turned | 12 | * - On the Hercules Game Theater XP the amplifier are sometimes turned |
13 | * off on inadecuate moments which causes distorcions on sound. | 13 | * off on inadecuate moments which causes distorcions on sound. |
14 | * | 14 | * |
@@ -45,7 +45,6 @@ | |||
45 | * | 45 | * |
46 | */ | 46 | */ |
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
51 | #include <linux/pm.h> | 50 | #include <linux/pm.h> |
@@ -2084,71 +2083,6 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, | |||
2084 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ | 2083 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ |
2085 | 2084 | ||
2086 | 2085 | ||
2087 | #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO | ||
2088 | static int snd_cs46xx_egpio_select_info(struct snd_kcontrol *kcontrol, | ||
2089 | struct snd_ctl_elem_info *uinfo) | ||
2090 | { | ||
2091 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2092 | uinfo->count = 1; | ||
2093 | uinfo->value.integer.min = 0; | ||
2094 | uinfo->value.integer.max = 8; | ||
2095 | return 0; | ||
2096 | } | ||
2097 | |||
2098 | static int snd_cs46xx_egpio_select_get(struct snd_kcontrol *kcontrol, | ||
2099 | struct snd_ctl_elem_value *ucontrol) | ||
2100 | { | ||
2101 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2102 | ucontrol->value.integer.value[0] = chip->current_gpio; | ||
2103 | |||
2104 | return 0; | ||
2105 | } | ||
2106 | |||
2107 | static int snd_cs46xx_egpio_select_put(struct snd_kcontrol *kcontrol, | ||
2108 | struct snd_ctl_elem_value *ucontrol) | ||
2109 | { | ||
2110 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2111 | int change = (chip->current_gpio != ucontrol->value.integer.value[0]); | ||
2112 | chip->current_gpio = ucontrol->value.integer.value[0]; | ||
2113 | |||
2114 | return change; | ||
2115 | } | ||
2116 | |||
2117 | |||
2118 | static int snd_cs46xx_egpio_get(struct snd_kcontrol *kcontrol, | ||
2119 | struct snd_ctl_elem_value *ucontrol) | ||
2120 | { | ||
2121 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2122 | int reg = kcontrol->private_value; | ||
2123 | |||
2124 | snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); | ||
2125 | ucontrol->value.integer.value[0] = | ||
2126 | (snd_cs46xx_peekBA0(chip, reg) & (1 << chip->current_gpio)) ? 1 : 0; | ||
2127 | |||
2128 | return 0; | ||
2129 | } | ||
2130 | |||
2131 | static int snd_cs46xx_egpio_put(struct snd_kcontrol *kcontrol, | ||
2132 | struct snd_ctl_elem_value *ucontrol) | ||
2133 | { | ||
2134 | struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol); | ||
2135 | int reg = kcontrol->private_value; | ||
2136 | int val = snd_cs46xx_peekBA0(chip, reg); | ||
2137 | int oldval = val; | ||
2138 | snd_printdd ("put: reg = %04x, gpio %02x\n",reg,chip->current_gpio); | ||
2139 | |||
2140 | if (ucontrol->value.integer.value[0]) | ||
2141 | val |= (1 << chip->current_gpio); | ||
2142 | else | ||
2143 | val &= ~(1 << chip->current_gpio); | ||
2144 | |||
2145 | snd_cs46xx_pokeBA0(chip, reg,val); | ||
2146 | snd_printdd ("put: val %08x oldval %08x\n",val,oldval); | ||
2147 | |||
2148 | return (oldval != val); | ||
2149 | } | ||
2150 | #endif /* CONFIG_SND_CS46XX_DEBUG_GPIO */ | ||
2151 | |||
2152 | static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { | 2086 | static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { |
2153 | { | 2087 | { |
2154 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2088 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -2241,40 +2175,6 @@ static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { | |||
2241 | }, | 2175 | }, |
2242 | 2176 | ||
2243 | #endif | 2177 | #endif |
2244 | #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO | ||
2245 | { | ||
2246 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2247 | .name = "EGPIO select", | ||
2248 | .info = snd_cs46xx_egpio_select_info, | ||
2249 | .get = snd_cs46xx_egpio_select_get, | ||
2250 | .put = snd_cs46xx_egpio_select_put, | ||
2251 | .private_value = 0, | ||
2252 | }, | ||
2253 | { | ||
2254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2255 | .name = "EGPIO Input/Output", | ||
2256 | .info = snd_mixer_boolean_info, | ||
2257 | .get = snd_cs46xx_egpio_get, | ||
2258 | .put = snd_cs46xx_egpio_put, | ||
2259 | .private_value = BA0_EGPIODR, | ||
2260 | }, | ||
2261 | { | ||
2262 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2263 | .name = "EGPIO CMOS/Open drain", | ||
2264 | .info = snd_mixer_boolean_info, | ||
2265 | .get = snd_cs46xx_egpio_get, | ||
2266 | .put = snd_cs46xx_egpio_put, | ||
2267 | .private_value = BA0_EGPIOPTR, | ||
2268 | }, | ||
2269 | { | ||
2270 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2271 | .name = "EGPIO On/Off", | ||
2272 | .info = snd_mixer_boolean_info, | ||
2273 | .get = snd_cs46xx_egpio_get, | ||
2274 | .put = snd_cs46xx_egpio_put, | ||
2275 | .private_value = BA0_EGPIOSR, | ||
2276 | }, | ||
2277 | #endif | ||
2278 | }; | 2178 | }; |
2279 | 2179 | ||
2280 | #ifdef CONFIG_SND_CS46XX_NEW_DSP | 2180 | #ifdef CONFIG_SND_CS46XX_NEW_DSP |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 590b35d91df2..ccc8bedb5b1a 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -20,7 +20,6 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | 23 | #include <asm/io.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index eded4dfeba12..2873cfe48c33 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/pm.h> | 26 | #include <linux/pm.h> |
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index 240a0a462209..7ff8b68e997e 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c | |||
@@ -36,7 +36,6 @@ | |||
36 | * same manner. | 36 | * same manner. |
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
41 | #include <linux/moduleparam.h> | 40 | #include <linux/moduleparam.h> |
42 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 2b35889787be..1d8b16052535 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -145,7 +144,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97, | |||
145 | return snd_cs5535audio_codec_read(cs5535au, reg); | 144 | return snd_cs5535audio_codec_read(cs5535au, reg); |
146 | } | 145 | } |
147 | 146 | ||
148 | static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) | 147 | static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) |
149 | { | 148 | { |
150 | struct snd_card *card = cs5535au->card; | 149 | struct snd_card *card = cs5535au->card; |
151 | struct snd_ac97_bus *pbus; | 150 | struct snd_ac97_bus *pbus; |
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 21df0634af32..cdcda87116c3 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
28 | #include <sound/driver.h> | ||
29 | #include <sound/core.h> | 28 | #include <sound/core.h> |
30 | #include <sound/control.h> | 29 | #include <sound/control.h> |
31 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
@@ -98,6 +97,8 @@ static int snd_cs5535audio_playback_open(struct snd_pcm_substream *substream) | |||
98 | struct snd_pcm_runtime *runtime = substream->runtime; | 97 | struct snd_pcm_runtime *runtime = substream->runtime; |
99 | 98 | ||
100 | runtime->hw = snd_cs5535audio_playback; | 99 | runtime->hw = snd_cs5535audio_playback; |
100 | runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_FRONT_DAC]; | ||
101 | snd_pcm_limit_hw_rates(runtime); | ||
101 | cs5535au->playback_substream = substream; | 102 | cs5535au->playback_substream = substream; |
102 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); | 103 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_PLAYBACK]); |
103 | if ((err = snd_pcm_hw_constraint_integer(runtime, | 104 | if ((err = snd_pcm_hw_constraint_integer(runtime, |
@@ -343,6 +344,8 @@ static int snd_cs5535audio_capture_open(struct snd_pcm_substream *substream) | |||
343 | struct snd_pcm_runtime *runtime = substream->runtime; | 344 | struct snd_pcm_runtime *runtime = substream->runtime; |
344 | 345 | ||
345 | runtime->hw = snd_cs5535audio_capture; | 346 | runtime->hw = snd_cs5535audio_capture; |
347 | runtime->hw.rates = cs5535au->ac97->rates[AC97_RATES_ADC]; | ||
348 | snd_pcm_limit_hw_rates(runtime); | ||
346 | cs5535au->capture_substream = substream; | 349 | cs5535au->capture_substream = substream; |
347 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); | 350 | runtime->private_data = &(cs5535au->dmas[CS5535AUDIO_DMA_CAPTURE]); |
348 | if ((err = snd_pcm_hw_constraint_integer(runtime, | 351 | if ((err = snd_pcm_hw_constraint_integer(runtime, |
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 838708f6d45e..564c33b60953 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include <sound/control.h> | 26 | #include <sound/control.h> |
28 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 87078d3a6854..8c6db3aa3c1a 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #define BX_NUM 10 | 36 | #define BX_NUM 10 |
37 | 37 | ||
38 | 38 | ||
39 | #include <sound/driver.h> | ||
40 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
41 | #include <linux/init.h> | 40 | #include <linux/init.h> |
42 | #include <linux/interrupt.h> | 41 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 42b48f9d2128..04cbf3eaf05a 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #define BX_NUM 10 | 40 | #define BX_NUM 10 |
41 | 41 | ||
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 8dbb7ac865c1..4022e43a0053 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #define BX_NUM chip->bx_num | 47 | #define BX_NUM chip->bx_num |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 499ee1a5319d..90ec090792ba 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -378,7 +378,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) | |||
378 | 378 | ||
379 | DE_ACT(("pcm_digital_in_open\n")); | 379 | DE_ACT(("pcm_digital_in_open\n")); |
380 | max_channels = num_digital_busses_in(chip) - substream->number; | 380 | max_channels = num_digital_busses_in(chip) - substream->number; |
381 | down(&chip->mode_mutex); | 381 | mutex_lock(&chip->mode_mutex); |
382 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 382 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
383 | err = pcm_open(substream, max_channels); | 383 | err = pcm_open(substream, max_channels); |
384 | else /* If the card has ADAT, subtract the 6 channels | 384 | else /* If the card has ADAT, subtract the 6 channels |
@@ -405,7 +405,7 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream) | |||
405 | chip->can_set_rate=0; | 405 | chip->can_set_rate=0; |
406 | 406 | ||
407 | din_exit: | 407 | din_exit: |
408 | up(&chip->mode_mutex); | 408 | mutex_unlock(&chip->mode_mutex); |
409 | return err; | 409 | return err; |
410 | } | 410 | } |
411 | 411 | ||
@@ -420,7 +420,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) | |||
420 | 420 | ||
421 | DE_ACT(("pcm_digital_out_open\n")); | 421 | DE_ACT(("pcm_digital_out_open\n")); |
422 | max_channels = num_digital_busses_out(chip) - substream->number; | 422 | max_channels = num_digital_busses_out(chip) - substream->number; |
423 | down(&chip->mode_mutex); | 423 | mutex_lock(&chip->mode_mutex); |
424 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 424 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
425 | err = pcm_open(substream, max_channels); | 425 | err = pcm_open(substream, max_channels); |
426 | else /* If the card has ADAT, subtract the 6 channels | 426 | else /* If the card has ADAT, subtract the 6 channels |
@@ -447,7 +447,7 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream) | |||
447 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 447 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) |
448 | chip->can_set_rate=0; | 448 | chip->can_set_rate=0; |
449 | dout_exit: | 449 | dout_exit: |
450 | up(&chip->mode_mutex); | 450 | mutex_unlock(&chip->mode_mutex); |
451 | return err; | 451 | return err; |
452 | } | 452 | } |
453 | 453 | ||
@@ -1420,7 +1420,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | |||
1420 | if (dmode != chip->digital_mode) { | 1420 | if (dmode != chip->digital_mode) { |
1421 | /* mode_mutex is required to make this operation atomic wrt | 1421 | /* mode_mutex is required to make this operation atomic wrt |
1422 | pcm_digital_*_open() and set_input_clock() functions. */ | 1422 | pcm_digital_*_open() and set_input_clock() functions. */ |
1423 | down(&chip->mode_mutex); | 1423 | mutex_lock(&chip->mode_mutex); |
1424 | 1424 | ||
1425 | /* Do not allow the user to change the digital mode when a pcm | 1425 | /* Do not allow the user to change the digital mode when a pcm |
1426 | device is open because it also changes the number of channels | 1426 | device is open because it also changes the number of channels |
@@ -1439,7 +1439,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | |||
1439 | if (changed >= 0) | 1439 | if (changed >= 0) |
1440 | changed = 1; /* No errors */ | 1440 | changed = 1; /* No errors */ |
1441 | } | 1441 | } |
1442 | up(&chip->mode_mutex); | 1442 | mutex_unlock(&chip->mode_mutex); |
1443 | } | 1443 | } |
1444 | return changed; | 1444 | return changed; |
1445 | } | 1445 | } |
@@ -1566,12 +1566,12 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, | |||
1566 | return -EINVAL; | 1566 | return -EINVAL; |
1567 | dclock = chip->clock_source_list[eclock]; | 1567 | dclock = chip->clock_source_list[eclock]; |
1568 | if (chip->input_clock != dclock) { | 1568 | if (chip->input_clock != dclock) { |
1569 | down(&chip->mode_mutex); | 1569 | mutex_lock(&chip->mode_mutex); |
1570 | spin_lock_irq(&chip->lock); | 1570 | spin_lock_irq(&chip->lock); |
1571 | if ((changed = set_input_clock(chip, dclock)) == 0) | 1571 | if ((changed = set_input_clock(chip, dclock)) == 0) |
1572 | changed = 1; /* no errors */ | 1572 | changed = 1; /* no errors */ |
1573 | spin_unlock_irq(&chip->lock); | 1573 | spin_unlock_irq(&chip->lock); |
1574 | up(&chip->mode_mutex); | 1574 | mutex_unlock(&chip->mode_mutex); |
1575 | } | 1575 | } |
1576 | 1576 | ||
1577 | if (changed < 0) | 1577 | if (changed < 0) |
@@ -1972,7 +1972,7 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
1972 | return err; | 1972 | return err; |
1973 | } | 1973 | } |
1974 | atomic_set(&chip->opencount, 0); | 1974 | atomic_set(&chip->opencount, 0); |
1975 | init_MUTEX(&chip->mode_mutex); | 1975 | mutex_init(&chip->mode_mutex); |
1976 | chip->can_set_rate = 1; | 1976 | chip->can_set_rate = 1; |
1977 | *rchip = chip; | 1977 | *rchip = chip; |
1978 | /* Init done ! */ | 1978 | /* Init done ! */ |
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index 7e88c968e22f..1c88e051abf2 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h | |||
@@ -361,7 +361,7 @@ struct echoaudio { | |||
361 | spinlock_t lock; | 361 | spinlock_t lock; |
362 | struct snd_pcm_substream *substream[DSP_MAXPIPES]; | 362 | struct snd_pcm_substream *substream[DSP_MAXPIPES]; |
363 | int last_period[DSP_MAXPIPES]; | 363 | int last_period[DSP_MAXPIPES]; |
364 | struct semaphore mode_mutex; | 364 | struct mutex mode_mutex; |
365 | u16 num_digital_modes, digital_mode_list[6]; | 365 | u16 num_digital_modes, digital_mode_list[6]; |
366 | u16 num_clock_sources, clock_source_list[10]; | 366 | u16 num_clock_sources, clock_source_list[10]; |
367 | atomic_t opencount; | 367 | atomic_t opencount; |
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index fee2d4831732..c0e64b8f52a4 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #define BX_NUM 14 | 40 | #define BX_NUM 14 |
41 | 41 | ||
42 | 42 | ||
43 | #include <sound/driver.h> | ||
44 | #include <linux/delay.h> | 43 | #include <linux/delay.h> |
45 | #include <linux/init.h> | 44 | #include <linux/init.h> |
46 | #include <linux/interrupt.h> | 45 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index d5eae470fe9a..c36a78dd0b5e 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #define BX_NUM 26 | 46 | #define BX_NUM 26 |
47 | 47 | ||
48 | 48 | ||
49 | #include <sound/driver.h> | ||
50 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
51 | #include <linux/init.h> | 50 | #include <linux/init.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 40f601cd016f..0a58a7c1fd7c 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #define BX_NUM 2 | 38 | #define BX_NUM 2 |
39 | 39 | ||
40 | 40 | ||
41 | #include <sound/driver.h> | ||
42 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
43 | #include <linux/init.h> | 42 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 771c5383210d..2db24d29332b 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #define BX_NUM 4 | 38 | #define BX_NUM 4 |
39 | 39 | ||
40 | 40 | ||
41 | #include <sound/driver.h> | ||
42 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
43 | #include <linux/init.h> | 42 | #include <linux/init.h> |
44 | #include <linux/interrupt.h> | 43 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index 49c550defcf9..a60c0a0a89b7 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #define BX_NUM 4 | 39 | #define BX_NUM 4 |
40 | 40 | ||
41 | 41 | ||
42 | #include <sound/driver.h> | ||
43 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
44 | #include <linux/init.h> | 43 | #include <linux/init.h> |
45 | #include <linux/interrupt.h> | 44 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 8f5483a405ae..506194688995 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #define BX_NUM 22 | 45 | #define BX_NUM 22 |
46 | 46 | ||
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
51 | #include <linux/interrupt.h> | 50 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index 0524667c02f7..e09e3ea7781e 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #define BX_NUM 32 | 47 | #define BX_NUM 32 |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index 893c7c20dd70..f3b9b45c9c1b 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #define BX_NUM 8 | 45 | #define BX_NUM 8 |
46 | 46 | ||
47 | 47 | ||
48 | #include <sound/driver.h> | ||
49 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
50 | #include <linux/init.h> | 49 | #include <linux/init.h> |
51 | #include <linux/interrupt.h> | 50 | #include <linux/interrupt.h> |
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index 3a5d5b0020df..b05bad944901 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #define BX_NUM 26 | 44 | #define BX_NUM 26 |
45 | 45 | ||
46 | 46 | ||
47 | #include <sound/driver.h> | ||
48 | #include <linux/delay.h> | 47 | #include <linux/delay.h> |
49 | #include <linux/init.h> | 48 | #include <linux/init.h> |
50 | #include <linux/interrupt.h> | 49 | #include <linux/interrupt.h> |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 9680caff90c8..8354c1a83312 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 01965bd99966..45088ebcce50 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c | |||
@@ -35,9 +35,9 @@ struct best_voice { | |||
35 | /* | 35 | /* |
36 | * prototypes | 36 | * prototypes |
37 | */ | 37 | */ |
38 | static void lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, | 38 | static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw, |
39 | struct best_voice *best, int active_only); | 39 | struct best_voice *best, int active_only); |
40 | static struct snd_emux_voice *get_voice(struct snd_emux *emu, | 40 | static struct snd_emux_voice *get_voice(struct snd_emux *emux, |
41 | struct snd_emux_port *port); | 41 | struct snd_emux_port *port); |
42 | static int start_voice(struct snd_emux_voice *vp); | 42 | static int start_voice(struct snd_emux_voice *vp); |
43 | static void trigger_voice(struct snd_emux_voice *vp); | 43 | static void trigger_voice(struct snd_emux_voice *vp); |
@@ -45,7 +45,6 @@ static void release_voice(struct snd_emux_voice *vp); | |||
45 | static void update_voice(struct snd_emux_voice *vp, int update); | 45 | static void update_voice(struct snd_emux_voice *vp, int update); |
46 | static void terminate_voice(struct snd_emux_voice *vp); | 46 | static void terminate_voice(struct snd_emux_voice *vp); |
47 | static void free_voice(struct snd_emux_voice *vp); | 47 | static void free_voice(struct snd_emux_voice *vp); |
48 | |||
49 | static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 48 | static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
50 | static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 49 | static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
51 | static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); | 50 | static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); |
@@ -75,9 +74,9 @@ static struct snd_emux_operators emu10k1_ops = { | |||
75 | }; | 74 | }; |
76 | 75 | ||
77 | void | 76 | void |
78 | snd_emu10k1_ops_setup(struct snd_emux *emu) | 77 | snd_emu10k1_ops_setup(struct snd_emux *emux) |
79 | { | 78 | { |
80 | emu->ops = emu10k1_ops; | 79 | emux->ops = emu10k1_ops; |
81 | } | 80 | } |
82 | 81 | ||
83 | 82 | ||
@@ -166,7 +165,11 @@ free_voice(struct snd_emux_voice *vp) | |||
166 | struct snd_emu10k1 *hw; | 165 | struct snd_emu10k1 *hw; |
167 | 166 | ||
168 | hw = vp->hw; | 167 | hw = vp->hw; |
169 | if (vp->ch >= 0) { | 168 | /* FIXME: emu10k1_synth is broken. */ |
169 | /* This can get called with hw == 0 */ | ||
170 | /* Problem apparent on plug, unplug then plug */ | ||
171 | /* on the Audigy 2 ZS Notebook. */ | ||
172 | if (hw && (vp->ch >= 0)) { | ||
170 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); | 173 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); |
171 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); | 174 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); |
172 | // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); | 175 | // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 97c41d72a255..9a9b977d3cf1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -33,7 +33,6 @@ | |||
33 | 33 | ||
34 | #include <linux/sched.h> | 34 | #include <linux/sched.h> |
35 | #include <linux/kthread.h> | 35 | #include <linux/kthread.h> |
36 | #include <sound/driver.h> | ||
37 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
38 | #include <linux/init.h> | 37 | #include <linux/init.h> |
39 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -55,12 +54,14 @@ | |||
55 | #define DOCK_FILENAME "emu/audio_dock.fw" | 54 | #define DOCK_FILENAME "emu/audio_dock.fw" |
56 | #define EMU1010B_FILENAME "emu/emu1010b.fw" | 55 | #define EMU1010B_FILENAME "emu/emu1010b.fw" |
57 | #define MICRO_DOCK_FILENAME "emu/micro_dock.fw" | 56 | #define MICRO_DOCK_FILENAME "emu/micro_dock.fw" |
57 | #define EMU0404_FILENAME "emu/emu0404.fw" | ||
58 | #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw" | 58 | #define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw" |
59 | 59 | ||
60 | MODULE_FIRMWARE(HANA_FILENAME); | 60 | MODULE_FIRMWARE(HANA_FILENAME); |
61 | MODULE_FIRMWARE(DOCK_FILENAME); | 61 | MODULE_FIRMWARE(DOCK_FILENAME); |
62 | MODULE_FIRMWARE(EMU1010B_FILENAME); | 62 | MODULE_FIRMWARE(EMU1010B_FILENAME); |
63 | MODULE_FIRMWARE(MICRO_DOCK_FILENAME); | 63 | MODULE_FIRMWARE(MICRO_DOCK_FILENAME); |
64 | MODULE_FIRMWARE(EMU0404_FILENAME); | ||
64 | MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); | 65 | MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); |
65 | 66 | ||
66 | 67 | ||
@@ -258,7 +259,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
258 | * GPIO7: Unknown | 259 | * GPIO7: Unknown |
259 | */ | 260 | */ |
260 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ | 261 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ |
261 | |||
262 | } | 262 | } |
263 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ | 263 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ |
264 | int size, n; | 264 | int size, n; |
@@ -274,7 +274,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
274 | emu->i2c_capture_volume[n][0]= 0xcf; | 274 | emu->i2c_capture_volume[n][0]= 0xcf; |
275 | emu->i2c_capture_volume[n][1]= 0xcf; | 275 | emu->i2c_capture_volume[n][1]= 0xcf; |
276 | } | 276 | } |
277 | |||
278 | } | 277 | } |
279 | 278 | ||
280 | 279 | ||
@@ -288,7 +287,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
288 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); | 287 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); |
289 | } | 288 | } |
290 | 289 | ||
291 | if (emu->card_capabilities->emu1010) { | 290 | if (emu->card_capabilities->emu_model) { |
292 | outl(HCFG_AUTOMUTE_ASYNC | | 291 | outl(HCFG_AUTOMUTE_ASYNC | |
293 | HCFG_EMU32_SLAVE | | 292 | HCFG_EMU32_SLAVE | |
294 | HCFG_AUDIOENABLE, emu->port + HCFG); | 293 | HCFG_AUDIOENABLE, emu->port + HCFG); |
@@ -318,7 +317,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
318 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | 317 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); |
319 | 318 | ||
320 | if (enable_ir) { /* enable IR for SB Live */ | 319 | if (enable_ir) { /* enable IR for SB Live */ |
321 | if (emu->card_capabilities->emu1010) { | 320 | if (emu->card_capabilities->emu_model) { |
322 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 321 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
323 | } else if (emu->card_capabilities->i2c_adc) { | 322 | } else if (emu->card_capabilities->i2c_adc) { |
324 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 323 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -339,7 +338,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
339 | } | 338 | } |
340 | } | 339 | } |
341 | 340 | ||
342 | if (emu->card_capabilities->emu1010) { | 341 | if (emu->card_capabilities->emu_model) { |
343 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 342 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
344 | } else if (emu->card_capabilities->i2c_adc) { | 343 | } else if (emu->card_capabilities->i2c_adc) { |
345 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 344 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -359,7 +358,7 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) | |||
359 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); | 358 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); |
360 | 359 | ||
361 | /* Enable analog/digital outs on audigy */ | 360 | /* Enable analog/digital outs on audigy */ |
362 | if (emu->card_capabilities->emu1010) { | 361 | if (emu->card_capabilities->emu_model) { |
363 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 362 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
364 | } else if (emu->card_capabilities->i2c_adc) { | 363 | } else if (emu->card_capabilities->i2c_adc) { |
365 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | 364 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ |
@@ -652,6 +651,8 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu) | |||
652 | value = inl(special_port); | 651 | value = inl(special_port); |
653 | 652 | ||
654 | snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ | 653 | snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ |
654 | /* Delay to give time for ADC chip to switch on. It needs 113ms */ | ||
655 | msleep(200); | ||
655 | return 0; | 656 | return 0; |
656 | } | 657 | } |
657 | 658 | ||
@@ -661,6 +662,8 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
661 | int n, i; | 662 | int n, i; |
662 | int reg; | 663 | int reg; |
663 | int value; | 664 | int value; |
665 | unsigned int write_post; | ||
666 | unsigned long flags; | ||
664 | const struct firmware *fw_entry; | 667 | const struct firmware *fw_entry; |
665 | 668 | ||
666 | if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { | 669 | if ((err = request_firmware(&fw_entry, filename, &emu->pci->dev)) != 0) { |
@@ -668,12 +671,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
668 | return err; | 671 | return err; |
669 | } | 672 | } |
670 | snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); | 673 | snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size); |
671 | #if 0 | ||
672 | if (fw_entry->size != 0x133a4) { | ||
673 | snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename); | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | #endif | ||
677 | 674 | ||
678 | /* The FPGA is a Xilinx Spartan IIE XC2S50E */ | 675 | /* The FPGA is a Xilinx Spartan IIE XC2S50E */ |
679 | /* GPIO7 -> FPGA PGMN | 676 | /* GPIO7 -> FPGA PGMN |
@@ -681,9 +678,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
681 | * GPIO5 -> FPGA DIN | 678 | * GPIO5 -> FPGA DIN |
682 | * FPGA CONFIG OFF -> FPGA PGMN | 679 | * FPGA CONFIG OFF -> FPGA PGMN |
683 | */ | 680 | */ |
681 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
684 | outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ | 682 | outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ |
685 | udelay(1); | 683 | write_post = inl(emu->port + A_IOCFG); |
684 | udelay(100); | ||
686 | outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ | 685 | outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ |
686 | write_post = inl(emu->port + A_IOCFG); | ||
687 | udelay(100); /* Allow FPGA memory to clean */ | 687 | udelay(100); /* Allow FPGA memory to clean */ |
688 | for(n = 0; n < fw_entry->size; n++) { | 688 | for(n = 0; n < fw_entry->size; n++) { |
689 | value=fw_entry->data[n]; | 689 | value=fw_entry->data[n]; |
@@ -693,18 +693,22 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file | |||
693 | reg = reg | 0x20; | 693 | reg = reg | 0x20; |
694 | value = value >> 1; | 694 | value = value >> 1; |
695 | outl(reg, emu->port + A_IOCFG); | 695 | outl(reg, emu->port + A_IOCFG); |
696 | write_post = inl(emu->port + A_IOCFG); | ||
696 | outl(reg | 0x40, emu->port + A_IOCFG); | 697 | outl(reg | 0x40, emu->port + A_IOCFG); |
698 | write_post = inl(emu->port + A_IOCFG); | ||
697 | } | 699 | } |
698 | } | 700 | } |
699 | /* After programming, set GPIO bit 4 high again. */ | 701 | /* After programming, set GPIO bit 4 high again. */ |
700 | outl(0x10, emu->port + A_IOCFG); | 702 | outl(0x10, emu->port + A_IOCFG); |
701 | 703 | write_post = inl(emu->port + A_IOCFG); | |
704 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
702 | 705 | ||
703 | release_firmware(fw_entry); | 706 | release_firmware(fw_entry); |
704 | return 0; | 707 | return 0; |
705 | } | 708 | } |
706 | 709 | ||
707 | int emu1010_firmware_thread(void *data) { | 710 | static int emu1010_firmware_thread(void *data) |
711 | { | ||
708 | struct snd_emu10k1 * emu = data; | 712 | struct snd_emu10k1 * emu = data; |
709 | int tmp,tmp2; | 713 | int tmp,tmp2; |
710 | int reg; | 714 | int reg; |
@@ -712,7 +716,7 @@ int emu1010_firmware_thread(void *data) { | |||
712 | 716 | ||
713 | for (;;) { | 717 | for (;;) { |
714 | /* Delay to allow Audio Dock to settle */ | 718 | /* Delay to allow Audio Dock to settle */ |
715 | msleep(1000); | 719 | msleep_interruptible(1000); |
716 | if (kthread_should_stop()) | 720 | if (kthread_should_stop()) |
717 | break; | 721 | break; |
718 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ | 722 | snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp ); /* IRQ Status */ |
@@ -722,17 +726,20 @@ int emu1010_firmware_thread(void *data) { | |||
722 | /* Return to Audio Dock programming mode */ | 726 | /* Return to Audio Dock programming mode */ |
723 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); | 727 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); |
724 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); | 728 | snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK ); |
725 | if (emu->card_capabilities->emu1010 == 1) { | 729 | if (emu->card_capabilities->emu_model == |
730 | EMU_MODEL_EMU1010) { | ||
726 | if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { | 731 | if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) { |
727 | return err; | 732 | continue; |
728 | } | 733 | } |
729 | } else if (emu->card_capabilities->emu1010 == 2) { | 734 | } else if (emu->card_capabilities->emu_model == |
735 | EMU_MODEL_EMU1010B) { | ||
730 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { | 736 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { |
731 | return err; | 737 | continue; |
732 | } | 738 | } |
733 | } else if (emu->card_capabilities->emu1010 == 3) { | 739 | } else if (emu->card_capabilities->emu_model == |
740 | EMU_MODEL_EMU1616) { | ||
734 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { | 741 | if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) { |
735 | return err; | 742 | continue; |
736 | } | 743 | } |
737 | } | 744 | } |
738 | 745 | ||
@@ -745,8 +752,7 @@ int emu1010_firmware_thread(void *data) { | |||
745 | if ((reg & 0x1f) != 0x15) { | 752 | if ((reg & 0x1f) != 0x15) { |
746 | /* FPGA failed to be programmed */ | 753 | /* FPGA failed to be programmed */ |
747 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); | 754 | snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg); |
748 | return 0; | 755 | continue; |
749 | return -ENODEV; | ||
750 | } | 756 | } |
751 | snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); | 757 | snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); |
752 | snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); | 758 | snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp ); |
@@ -757,9 +763,9 @@ int emu1010_firmware_thread(void *data) { | |||
757 | msleep(10); | 763 | msleep(10); |
758 | /* Unmute all. Default is muted after a firmware load */ | 764 | /* Unmute all. Default is muted after a firmware load */ |
759 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); | 765 | snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); |
760 | break; | ||
761 | } | 766 | } |
762 | } | 767 | } |
768 | snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); | ||
763 | return 0; | 769 | return 0; |
764 | } | 770 | } |
765 | 771 | ||
@@ -800,6 +806,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
800 | int tmp,tmp2; | 806 | int tmp,tmp2; |
801 | int reg; | 807 | int reg; |
802 | int err; | 808 | int err; |
809 | const char *filename = NULL; | ||
803 | 810 | ||
804 | snd_printk(KERN_INFO "emu1010: Special config.\n"); | 811 | snd_printk(KERN_INFO "emu1010: Special config.\n"); |
805 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, | 812 | /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, |
@@ -841,21 +848,31 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
841 | return -ENODEV; | 848 | return -ENODEV; |
842 | } | 849 | } |
843 | snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); | 850 | snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg); |
844 | if (emu->card_capabilities->emu1010 == 1) { | 851 | switch (emu->card_capabilities->emu_model) { |
845 | if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) { | 852 | case EMU_MODEL_EMU1010: |
846 | snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME); | 853 | filename = HANA_FILENAME; |
847 | return err; | 854 | break; |
848 | } | 855 | case EMU_MODEL_EMU1010B: |
849 | } else if (emu->card_capabilities->emu1010 == 2) { | 856 | filename = EMU1010B_FILENAME; |
850 | if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) { | 857 | break; |
851 | snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME); | 858 | case EMU_MODEL_EMU1616: |
852 | return err; | 859 | filename = EMU1010_NOTEBOOK_FILENAME; |
853 | } | 860 | break; |
854 | } else if (emu->card_capabilities->emu1010 == 3) { | 861 | case EMU_MODEL_EMU0404: |
855 | if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) { | 862 | filename = EMU0404_FILENAME; |
856 | snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME); | 863 | break; |
857 | return err; | 864 | default: |
858 | } | 865 | filename = NULL; |
866 | return -ENODEV; | ||
867 | break; | ||
868 | } | ||
869 | snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename); | ||
870 | err = snd_emu1010_load_firmware(emu, filename); | ||
871 | if (err != 0) { | ||
872 | snd_printk( | ||
873 | KERN_INFO "emu1010: Loading Firmware file %s failed\n", | ||
874 | filename); | ||
875 | return err; | ||
859 | } | 876 | } |
860 | 877 | ||
861 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ | 878 | /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ |
@@ -1074,10 +1091,12 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
1074 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ | 1091 | snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10 ); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ |
1075 | 1092 | ||
1076 | /* Start Micro/Audio Dock firmware loader thread */ | 1093 | /* Start Micro/Audio Dock firmware loader thread */ |
1077 | emu->emu1010.firmware_thread = kthread_create(&emu1010_firmware_thread, | 1094 | if (!emu->emu1010.firmware_thread) { |
1078 | emu, | 1095 | emu->emu1010.firmware_thread = |
1079 | "emu1010_firmware"); | 1096 | kthread_create(emu1010_firmware_thread, emu, |
1080 | wake_up_process(emu->emu1010.firmware_thread); | 1097 | "emu1010_firmware"); |
1098 | wake_up_process(emu->emu1010.firmware_thread); | ||
1099 | } | ||
1081 | 1100 | ||
1082 | #if 0 | 1101 | #if 0 |
1083 | snd_emu1010_fpga_link_dst_src_write(emu, | 1102 | snd_emu1010_fpga_link_dst_src_write(emu, |
@@ -1090,79 +1109,114 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu) | |||
1090 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ | 1109 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ |
1091 | #endif | 1110 | #endif |
1092 | /* Default outputs */ | 1111 | /* Default outputs */ |
1093 | snd_emu1010_fpga_link_dst_src_write(emu, | 1112 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
1094 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1113 | /* 1616(M) cardbus default outputs */ |
1095 | emu->emu1010.output_source[0] = 21; | 1114 | /* ALICE2 bus 0xa0 */ |
1096 | snd_emu1010_fpga_link_dst_src_write(emu, | 1115 | snd_emu1010_fpga_link_dst_src_write(emu, |
1097 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1116 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1098 | emu->emu1010.output_source[1] = 22; | 1117 | emu->emu1010.output_source[0] = 17; |
1099 | snd_emu1010_fpga_link_dst_src_write(emu, | 1118 | snd_emu1010_fpga_link_dst_src_write(emu, |
1100 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); | 1119 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1101 | emu->emu1010.output_source[2] = 23; | 1120 | emu->emu1010.output_source[1] = 18; |
1102 | snd_emu1010_fpga_link_dst_src_write(emu, | 1121 | snd_emu1010_fpga_link_dst_src_write(emu, |
1103 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); | 1122 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); |
1104 | emu->emu1010.output_source[3] = 24; | 1123 | emu->emu1010.output_source[2] = 19; |
1105 | snd_emu1010_fpga_link_dst_src_write(emu, | 1124 | snd_emu1010_fpga_link_dst_src_write(emu, |
1106 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); | 1125 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); |
1107 | emu->emu1010.output_source[4] = 25; | 1126 | emu->emu1010.output_source[3] = 20; |
1108 | snd_emu1010_fpga_link_dst_src_write(emu, | 1127 | snd_emu1010_fpga_link_dst_src_write(emu, |
1109 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); | 1128 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); |
1110 | emu->emu1010.output_source[5] = 26; | 1129 | emu->emu1010.output_source[4] = 21; |
1111 | snd_emu1010_fpga_link_dst_src_write(emu, | 1130 | snd_emu1010_fpga_link_dst_src_write(emu, |
1112 | EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); | 1131 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); |
1113 | emu->emu1010.output_source[6] = 27; | 1132 | emu->emu1010.output_source[5] = 22; |
1114 | snd_emu1010_fpga_link_dst_src_write(emu, | 1133 | /* ALICE2 bus 0xa0 */ |
1115 | EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); | 1134 | snd_emu1010_fpga_link_dst_src_write(emu, |
1116 | emu->emu1010.output_source[7] = 28; | 1135 | EMU_DST_MANA_DAC_LEFT, EMU_SRC_ALICE_EMU32A + 0); |
1117 | snd_emu1010_fpga_link_dst_src_write(emu, | 1136 | emu->emu1010.output_source[16] = 17; |
1118 | EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1137 | snd_emu1010_fpga_link_dst_src_write(emu, |
1119 | emu->emu1010.output_source[8] = 21; | 1138 | EMU_DST_MANA_DAC_RIGHT, EMU_SRC_ALICE_EMU32A + 1); |
1120 | snd_emu1010_fpga_link_dst_src_write(emu, | 1139 | emu->emu1010.output_source[17] = 18; |
1121 | EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1140 | } else { |
1122 | emu->emu1010.output_source[9] = 22; | 1141 | /* ALICE2 bus 0xa0 */ |
1123 | snd_emu1010_fpga_link_dst_src_write(emu, | 1142 | snd_emu1010_fpga_link_dst_src_write(emu, |
1124 | EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1143 | EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1125 | emu->emu1010.output_source[10] = 21; | 1144 | emu->emu1010.output_source[0] = 21; |
1126 | snd_emu1010_fpga_link_dst_src_write(emu, | 1145 | snd_emu1010_fpga_link_dst_src_write(emu, |
1127 | EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1146 | EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1128 | emu->emu1010.output_source[11] = 22; | 1147 | emu->emu1010.output_source[1] = 22; |
1129 | snd_emu1010_fpga_link_dst_src_write(emu, | 1148 | snd_emu1010_fpga_link_dst_src_write(emu, |
1130 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1149 | EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); |
1131 | emu->emu1010.output_source[12] = 21; | 1150 | emu->emu1010.output_source[2] = 23; |
1132 | snd_emu1010_fpga_link_dst_src_write(emu, | 1151 | snd_emu1010_fpga_link_dst_src_write(emu, |
1133 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1152 | EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); |
1134 | emu->emu1010.output_source[13] = 22; | 1153 | emu->emu1010.output_source[3] = 24; |
1135 | snd_emu1010_fpga_link_dst_src_write(emu, | 1154 | snd_emu1010_fpga_link_dst_src_write(emu, |
1136 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1155 | EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); |
1137 | emu->emu1010.output_source[14] = 21; | 1156 | emu->emu1010.output_source[4] = 25; |
1138 | snd_emu1010_fpga_link_dst_src_write(emu, | 1157 | snd_emu1010_fpga_link_dst_src_write(emu, |
1139 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | 1158 | EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); |
1140 | emu->emu1010.output_source[15] = 22; | 1159 | emu->emu1010.output_source[5] = 26; |
1141 | snd_emu1010_fpga_link_dst_src_write(emu, | 1160 | snd_emu1010_fpga_link_dst_src_write(emu, |
1142 | EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); /* ALICE2 bus 0xa0 */ | 1161 | EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); |
1143 | emu->emu1010.output_source[16] = 21; | 1162 | emu->emu1010.output_source[6] = 27; |
1144 | snd_emu1010_fpga_link_dst_src_write(emu, | 1163 | snd_emu1010_fpga_link_dst_src_write(emu, |
1145 | EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); | 1164 | EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); |
1146 | emu->emu1010.output_source[17] = 22; | 1165 | emu->emu1010.output_source[7] = 28; |
1147 | snd_emu1010_fpga_link_dst_src_write(emu, | 1166 | /* ALICE2 bus 0xa0 */ |
1148 | EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); | 1167 | snd_emu1010_fpga_link_dst_src_write(emu, |
1149 | emu->emu1010.output_source[18] = 23; | 1168 | EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1150 | snd_emu1010_fpga_link_dst_src_write(emu, | 1169 | emu->emu1010.output_source[8] = 21; |
1151 | EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); | 1170 | snd_emu1010_fpga_link_dst_src_write(emu, |
1152 | emu->emu1010.output_source[19] = 24; | 1171 | EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1153 | snd_emu1010_fpga_link_dst_src_write(emu, | 1172 | emu->emu1010.output_source[9] = 22; |
1154 | EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); | 1173 | /* ALICE2 bus 0xa0 */ |
1155 | emu->emu1010.output_source[20] = 25; | 1174 | snd_emu1010_fpga_link_dst_src_write(emu, |
1156 | snd_emu1010_fpga_link_dst_src_write(emu, | 1175 | EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1157 | EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); | 1176 | emu->emu1010.output_source[10] = 21; |
1158 | emu->emu1010.output_source[21] = 26; | 1177 | snd_emu1010_fpga_link_dst_src_write(emu, |
1159 | snd_emu1010_fpga_link_dst_src_write(emu, | 1178 | EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); |
1160 | EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); | 1179 | emu->emu1010.output_source[11] = 22; |
1161 | emu->emu1010.output_source[22] = 27; | 1180 | /* ALICE2 bus 0xa0 */ |
1162 | snd_emu1010_fpga_link_dst_src_write(emu, | 1181 | snd_emu1010_fpga_link_dst_src_write(emu, |
1163 | EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); | 1182 | EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); |
1164 | emu->emu1010.output_source[23] = 28; | 1183 | emu->emu1010.output_source[12] = 21; |
1165 | 1184 | snd_emu1010_fpga_link_dst_src_write(emu, | |
1185 | EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1186 | emu->emu1010.output_source[13] = 22; | ||
1187 | /* ALICE2 bus 0xa0 */ | ||
1188 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1189 | EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); | ||
1190 | emu->emu1010.output_source[14] = 21; | ||
1191 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1192 | EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); | ||
1193 | emu->emu1010.output_source[15] = 22; | ||
1194 | /* ALICE2 bus 0xa0 */ | ||
1195 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1196 | EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); | ||
1197 | emu->emu1010.output_source[16] = 21; | ||
1198 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1199 | EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); | ||
1200 | emu->emu1010.output_source[17] = 22; | ||
1201 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1202 | EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); | ||
1203 | emu->emu1010.output_source[18] = 23; | ||
1204 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1205 | EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); | ||
1206 | emu->emu1010.output_source[19] = 24; | ||
1207 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1208 | EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); | ||
1209 | emu->emu1010.output_source[20] = 25; | ||
1210 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1211 | EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); | ||
1212 | emu->emu1010.output_source[21] = 26; | ||
1213 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1214 | EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); | ||
1215 | emu->emu1010.output_source[22] = 27; | ||
1216 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
1217 | EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); | ||
1218 | emu->emu1010.output_source[23] = 28; | ||
1219 | } | ||
1166 | /* TEMP: Select SPDIF in/out */ | 1220 | /* TEMP: Select SPDIF in/out */ |
1167 | //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ | 1221 | //snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); /* Output spdif */ |
1168 | 1222 | ||
@@ -1202,11 +1256,12 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) | |||
1202 | } | 1256 | } |
1203 | snd_emu10k1_free_efx(emu); | 1257 | snd_emu10k1_free_efx(emu); |
1204 | } | 1258 | } |
1205 | if (emu->card_capabilities->emu1010) { | 1259 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) { |
1206 | /* Disable 48Volt power to Audio Dock */ | 1260 | /* Disable 48Volt power to Audio Dock */ |
1207 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); | 1261 | snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0 ); |
1208 | kthread_stop(emu->emu1010.firmware_thread); | ||
1209 | } | 1262 | } |
1263 | if (emu->emu1010.firmware_thread) | ||
1264 | kthread_stop(emu->emu1010.firmware_thread); | ||
1210 | if (emu->memhdr) | 1265 | if (emu->memhdr) |
1211 | snd_util_memhdr_free(emu->memhdr); | 1266 | snd_util_memhdr_free(emu->memhdr); |
1212 | if (emu->silent_page.area) | 1267 | if (emu->silent_page.area) |
@@ -1338,6 +1393,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1338 | .spi_dac = 1, | 1393 | .spi_dac = 1, |
1339 | .i2c_adc = 1, | 1394 | .i2c_adc = 1, |
1340 | .spk71 = 1} , | 1395 | .spk71 = 1} , |
1396 | /* Tested by James@superbug.co.uk 4th Nov 2007. */ | ||
1341 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, | 1397 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, |
1342 | .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", | 1398 | .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", |
1343 | .id = "EMU1010", | 1399 | .id = "EMU1010", |
@@ -1345,28 +1401,46 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1345 | .ca0108_chip = 1, | 1401 | .ca0108_chip = 1, |
1346 | .ca_cardbus_chip = 1, | 1402 | .ca_cardbus_chip = 1, |
1347 | .spk71 = 1 , | 1403 | .spk71 = 1 , |
1348 | .emu1010 = 3} , | 1404 | .emu_model = EMU_MODEL_EMU1616}, |
1405 | /* Tested by James@superbug.co.uk 4th Nov 2007. */ | ||
1349 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, | 1406 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, |
1350 | .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", | 1407 | .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", |
1351 | .id = "EMU1010", | 1408 | .id = "EMU1010", |
1352 | .emu10k2_chip = 1, | 1409 | .emu10k2_chip = 1, |
1353 | .ca0108_chip = 1, | 1410 | .ca0108_chip = 1, |
1354 | .spk71 = 1 , | 1411 | .spk71 = 1, |
1355 | .emu1010 = 2} , | 1412 | .emu_model = EMU_MODEL_EMU1010B}, |
1413 | /* Tested by James@superbug.co.uk 8th July 2005. */ | ||
1414 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, | ||
1415 | .driver = "Audigy2", .name = "E-mu 1010 [4001]", | ||
1416 | .id = "EMU1010", | ||
1417 | .emu10k2_chip = 1, | ||
1418 | .ca0102_chip = 1, | ||
1419 | .spk71 = 1, | ||
1420 | .emu_model = EMU_MODEL_EMU1010}, /* Emu 1010 */ | ||
1421 | /* EMU0404b */ | ||
1422 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, | ||
1423 | .driver = "Audigy2", .name = "E-mu 0404b [4002]", | ||
1424 | .id = "EMU0404", | ||
1425 | .emu10k2_chip = 1, | ||
1426 | .ca0108_chip = 1, | ||
1427 | .spk71 = 1, | ||
1428 | .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ | ||
1429 | /* Tested by James@superbug.co.uk 20-3-2007. */ | ||
1430 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, | ||
1431 | .driver = "Audigy2", .name = "E-mu 0404 [4002]", | ||
1432 | .id = "EMU0404", | ||
1433 | .emu10k2_chip = 1, | ||
1434 | .ca0102_chip = 1, | ||
1435 | .spk71 = 1, | ||
1436 | .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ | ||
1437 | /* Audigy4 (Not PRO) SB0610 */ | ||
1356 | {.vendor = 0x1102, .device = 0x0008, | 1438 | {.vendor = 0x1102, .device = 0x0008, |
1357 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 1439 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
1358 | .id = "Audigy2", | 1440 | .id = "Audigy2", |
1359 | .emu10k2_chip = 1, | 1441 | .emu10k2_chip = 1, |
1360 | .ca0108_chip = 1, | 1442 | .ca0108_chip = 1, |
1361 | .ac97_chip = 1} , | 1443 | .ac97_chip = 1} , |
1362 | /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */ | ||
1363 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, | ||
1364 | .driver = "Audigy2", .name = "E-mu 1010 [4001]", | ||
1365 | .id = "EMU1010", | ||
1366 | .emu10k2_chip = 1, | ||
1367 | .ca0102_chip = 1, | ||
1368 | .spk71 = 1, | ||
1369 | .emu1010 = 1} , | ||
1370 | /* Tested by James@superbug.co.uk 3rd July 2005 */ | 1444 | /* Tested by James@superbug.co.uk 3rd July 2005 */ |
1371 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, | 1445 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, |
1372 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", | 1446 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", |
@@ -1654,6 +1728,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1654 | emu->card = card; | 1728 | emu->card = card; |
1655 | spin_lock_init(&emu->reg_lock); | 1729 | spin_lock_init(&emu->reg_lock); |
1656 | spin_lock_init(&emu->emu_lock); | 1730 | spin_lock_init(&emu->emu_lock); |
1731 | spin_lock_init(&emu->spi_lock); | ||
1732 | spin_lock_init(&emu->i2c_lock); | ||
1657 | spin_lock_init(&emu->voice_lock); | 1733 | spin_lock_init(&emu->voice_lock); |
1658 | spin_lock_init(&emu->synth_lock); | 1734 | spin_lock_init(&emu->synth_lock); |
1659 | spin_lock_init(&emu->memblk_lock); | 1735 | spin_lock_init(&emu->memblk_lock); |
@@ -1794,7 +1870,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card, | |||
1794 | if (emu->card_capabilities->ecard) { | 1870 | if (emu->card_capabilities->ecard) { |
1795 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) | 1871 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) |
1796 | goto error; | 1872 | goto error; |
1797 | } else if (emu->card_capabilities->emu1010) { | 1873 | } else if (emu->card_capabilities->emu_model) { |
1798 | if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { | 1874 | if ((err = snd_emu10k1_emu1010_init(emu)) < 0) { |
1799 | snd_emu10k1_free(emu); | 1875 | snd_emu10k1_free(emu); |
1800 | return err; | 1876 | return err; |
@@ -1943,7 +2019,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) | |||
1943 | snd_emu10k1_cardbus_init(emu); | 2019 | snd_emu10k1_cardbus_init(emu); |
1944 | if (emu->card_capabilities->ecard) | 2020 | if (emu->card_capabilities->ecard) |
1945 | snd_emu10k1_ecard_init(emu); | 2021 | snd_emu10k1_ecard_init(emu); |
1946 | else if (emu->card_capabilities->emu1010) | 2022 | else if (emu->card_capabilities->emu_model) |
1947 | snd_emu10k1_emu1010_init(emu); | 2023 | snd_emu10k1_emu1010_init(emu); |
1948 | else | 2024 | else |
1949 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | 2025 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); |
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 204995a1dfbd..ad7b71491fc4 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c | |||
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL"); | |||
30 | */ | 30 | */ |
31 | static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) | 31 | static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) |
32 | { | 32 | { |
33 | struct snd_emux *emu; | 33 | struct snd_emux *emux; |
34 | struct snd_emu10k1 *hw; | 34 | struct snd_emu10k1 *hw; |
35 | struct snd_emu10k1_synth_arg *arg; | 35 | struct snd_emu10k1_synth_arg *arg; |
36 | unsigned long flags; | 36 | unsigned long flags; |
@@ -46,53 +46,56 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) | |||
46 | else if (arg->max_voices > 64) | 46 | else if (arg->max_voices > 64) |
47 | arg->max_voices = 64; | 47 | arg->max_voices = 64; |
48 | 48 | ||
49 | if (snd_emux_new(&emu) < 0) | 49 | if (snd_emux_new(&emux) < 0) |
50 | return -ENOMEM; | 50 | return -ENOMEM; |
51 | 51 | ||
52 | snd_emu10k1_ops_setup(emu); | 52 | snd_emu10k1_ops_setup(emux); |
53 | emu->hw = hw = arg->hwptr; | 53 | hw = arg->hwptr; |
54 | emu->max_voices = arg->max_voices; | 54 | emux->hw = hw; |
55 | emu->num_ports = arg->seq_ports; | 55 | emux->max_voices = arg->max_voices; |
56 | emu->pitch_shift = -501; | 56 | emux->num_ports = arg->seq_ports; |
57 | emu->memhdr = hw->memhdr; | 57 | emux->pitch_shift = -501; |
58 | emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */ | 58 | emux->memhdr = hw->memhdr; |
59 | emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */ | 59 | /* maximum two ports */ |
60 | emu->linear_panning = 0; | 60 | emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; |
61 | emu->hwdep_idx = 2; /* FIXED */ | 61 | /* audigy has two external midis */ |
62 | 62 | emux->midi_devidx = hw->audigy ? 2 : 1; | |
63 | if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { | 63 | emux->linear_panning = 0; |
64 | snd_emux_free(emu); | 64 | emux->hwdep_idx = 2; /* FIXED */ |
65 | |||
66 | if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) { | ||
67 | snd_emux_free(emux); | ||
65 | return -ENOMEM; | 68 | return -ENOMEM; |
66 | } | 69 | } |
67 | 70 | ||
68 | spin_lock_irqsave(&hw->voice_lock, flags); | 71 | spin_lock_irqsave(&hw->voice_lock, flags); |
69 | hw->synth = emu; | 72 | hw->synth = emux; |
70 | hw->get_synth_voice = snd_emu10k1_synth_get_voice; | 73 | hw->get_synth_voice = snd_emu10k1_synth_get_voice; |
71 | spin_unlock_irqrestore(&hw->voice_lock, flags); | 74 | spin_unlock_irqrestore(&hw->voice_lock, flags); |
72 | 75 | ||
73 | dev->driver_data = emu; | 76 | dev->driver_data = emux; |
74 | 77 | ||
75 | return 0; | 78 | return 0; |
76 | } | 79 | } |
77 | 80 | ||
78 | static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) | 81 | static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) |
79 | { | 82 | { |
80 | struct snd_emux *emu; | 83 | struct snd_emux *emux; |
81 | struct snd_emu10k1 *hw; | 84 | struct snd_emu10k1 *hw; |
82 | unsigned long flags; | 85 | unsigned long flags; |
83 | 86 | ||
84 | if (dev->driver_data == NULL) | 87 | if (dev->driver_data == NULL) |
85 | return 0; /* not registered actually */ | 88 | return 0; /* not registered actually */ |
86 | 89 | ||
87 | emu = dev->driver_data; | 90 | emux = dev->driver_data; |
88 | 91 | ||
89 | hw = emu->hw; | 92 | hw = emux->hw; |
90 | spin_lock_irqsave(&hw->voice_lock, flags); | 93 | spin_lock_irqsave(&hw->voice_lock, flags); |
91 | hw->synth = NULL; | 94 | hw->synth = NULL; |
92 | hw->get_synth_voice = NULL; | 95 | hw->get_synth_voice = NULL; |
93 | spin_unlock_irqrestore(&hw->voice_lock, flags); | 96 | spin_unlock_irqrestore(&hw->voice_lock, flags); |
94 | 97 | ||
95 | snd_emux_free(emu); | 98 | snd_emux_free(emux); |
96 | return 0; | 99 | return 0; |
97 | } | 100 | } |
98 | 101 | ||
diff --git a/sound/pci/emu10k1/emu10k1_synth_local.h b/sound/pci/emu10k1/emu10k1_synth_local.h index 308ddc84bb4d..25f328ff639f 100644 --- a/sound/pci/emu10k1/emu10k1_synth_local.h +++ b/sound/pci/emu10k1/emu10k1_synth_local.h | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
26 | #include <sound/emu10k1_synth.h> | 25 | #include <sound/emu10k1_synth.h> |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1ec7ebaff9e9..5512abd98bd9 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -29,7 +29,6 @@ | |||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | #include <sound/driver.h> | ||
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
35 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
@@ -1583,6 +1582,8 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, | |||
1583 | sprintf(card->longname, "%s at 0x%lx irq %i", | 1582 | sprintf(card->longname, "%s at 0x%lx irq %i", |
1584 | card->shortname, chip->port, chip->irq); | 1583 | card->shortname, chip->port, chip->irq); |
1585 | 1584 | ||
1585 | snd_card_set_dev(card, &pci->dev); | ||
1586 | |||
1586 | if ((err = snd_card_register(card)) < 0) { | 1587 | if ((err = snd_card_register(card)) < 0) { |
1587 | snd_card_free(card); | 1588 | snd_card_free(card); |
1588 | return err; | 1589 | return err; |
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 9bf1cd592199..71dc4c8865b8 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
33 | #include <linux/capability.h> | 32 | #include <linux/capability.h> |
34 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
@@ -666,7 +665,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv) | |||
666 | return NULL; | 665 | return NULL; |
667 | if (data[1] >= MAX_TLV_SIZE) | 666 | if (data[1] >= MAX_TLV_SIZE) |
668 | return NULL; | 667 | return NULL; |
669 | tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL); | 668 | tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL); |
670 | if (!tlv) | 669 | if (!tlv) |
671 | return NULL; | 670 | return NULL; |
672 | memcpy(tlv, data, sizeof(data)); | 671 | memcpy(tlv, data, sizeof(data)); |
@@ -1262,7 +1261,7 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) | |||
1262 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | 1261 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) |
1263 | 1262 | ||
1264 | /* emu1212 DSP 0 and DSP 1 Capture */ | 1263 | /* emu1212 DSP 0 and DSP 1 Capture */ |
1265 | if (emu->card_capabilities->emu1010) { | 1264 | if (emu->card_capabilities->emu_model) { |
1266 | if (emu->card_capabilities->ca0108_chip) { | 1265 | if (emu->card_capabilities->ca0108_chip) { |
1267 | /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ | 1266 | /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ |
1268 | A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); | 1267 | A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); |
@@ -1516,7 +1515,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1516 | 1515 | ||
1517 | /* digital outputs */ | 1516 | /* digital outputs */ |
1518 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ | 1517 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ |
1519 | if (emu->card_capabilities->emu1010) { | 1518 | if (emu->card_capabilities->emu_model) { |
1520 | /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ | 1519 | /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ |
1521 | snd_printk("EMU outputs on\n"); | 1520 | snd_printk("EMU outputs on\n"); |
1522 | for (z = 0; z < 8; z++) { | 1521 | for (z = 0; z < 8; z++) { |
@@ -1564,7 +1563,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | |||
1564 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); | 1563 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); |
1565 | #endif | 1564 | #endif |
1566 | 1565 | ||
1567 | if (emu->card_capabilities->emu1010) { | 1566 | if (emu->card_capabilities->emu_model) { |
1568 | if (emu->card_capabilities->ca0108_chip) { | 1567 | if (emu->card_capabilities->ca0108_chip) { |
1569 | snd_printk("EMU2 inputs on\n"); | 1568 | snd_printk("EMU2 inputs on\n"); |
1570 | for (z = 0; z < 0x10; z++) { | 1569 | for (z = 0; z < 0x10; z++) { |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 54a2034d8edd..fd221209abcb 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -30,7 +30,6 @@ | |||
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <sound/driver.h> | ||
34 | #include <linux/time.h> | 33 | #include <linux/time.h> |
35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
36 | #include <sound/core.h> | 35 | #include <sound/core.h> |
@@ -58,6 +57,9 @@ static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, | |||
58 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 57 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
59 | unsigned long flags; | 58 | unsigned long flags; |
60 | 59 | ||
60 | /* Limit: emu->spdif_bits */ | ||
61 | if (idx >= 3) | ||
62 | return -EINVAL; | ||
61 | spin_lock_irqsave(&emu->reg_lock, flags); | 63 | spin_lock_irqsave(&emu->reg_lock, flags); |
62 | ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; | 64 | ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; |
63 | ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; | 65 | ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; |
@@ -137,6 +139,61 @@ static char *emu1010_src_texts[] = { | |||
137 | "DSP 31", | 139 | "DSP 31", |
138 | }; | 140 | }; |
139 | 141 | ||
142 | /* 1616(m) cardbus */ | ||
143 | |||
144 | static char *emu1616_src_texts[] = { | ||
145 | "Silence", | ||
146 | "Dock Mic A", | ||
147 | "Dock Mic B", | ||
148 | "Dock ADC1 Left", | ||
149 | "Dock ADC1 Right", | ||
150 | "Dock ADC2 Left", | ||
151 | "Dock ADC2 Right", | ||
152 | "Dock SPDIF Left", | ||
153 | "Dock SPDIF Right", | ||
154 | "ADAT 0", | ||
155 | "ADAT 1", | ||
156 | "ADAT 2", | ||
157 | "ADAT 3", | ||
158 | "ADAT 4", | ||
159 | "ADAT 5", | ||
160 | "ADAT 6", | ||
161 | "ADAT 7", | ||
162 | "DSP 0", | ||
163 | "DSP 1", | ||
164 | "DSP 2", | ||
165 | "DSP 3", | ||
166 | "DSP 4", | ||
167 | "DSP 5", | ||
168 | "DSP 6", | ||
169 | "DSP 7", | ||
170 | "DSP 8", | ||
171 | "DSP 9", | ||
172 | "DSP 10", | ||
173 | "DSP 11", | ||
174 | "DSP 12", | ||
175 | "DSP 13", | ||
176 | "DSP 14", | ||
177 | "DSP 15", | ||
178 | "DSP 16", | ||
179 | "DSP 17", | ||
180 | "DSP 18", | ||
181 | "DSP 19", | ||
182 | "DSP 20", | ||
183 | "DSP 21", | ||
184 | "DSP 22", | ||
185 | "DSP 23", | ||
186 | "DSP 24", | ||
187 | "DSP 25", | ||
188 | "DSP 26", | ||
189 | "DSP 27", | ||
190 | "DSP 28", | ||
191 | "DSP 29", | ||
192 | "DSP 30", | ||
193 | "DSP 31", | ||
194 | }; | ||
195 | |||
196 | |||
140 | /* | 197 | /* |
141 | * List of data sources available for each destination | 198 | * List of data sources available for each destination |
142 | */ | 199 | */ |
@@ -196,6 +253,59 @@ static unsigned int emu1010_src_regs[] = { | |||
196 | EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ | 253 | EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ |
197 | }; | 254 | }; |
198 | 255 | ||
256 | /* 1616(m) cardbus */ | ||
257 | static unsigned int emu1616_src_regs[] = { | ||
258 | EMU_SRC_SILENCE, | ||
259 | EMU_SRC_DOCK_MIC_A1, | ||
260 | EMU_SRC_DOCK_MIC_B1, | ||
261 | EMU_SRC_DOCK_ADC1_LEFT1, | ||
262 | EMU_SRC_DOCK_ADC1_RIGHT1, | ||
263 | EMU_SRC_DOCK_ADC2_LEFT1, | ||
264 | EMU_SRC_DOCK_ADC2_RIGHT1, | ||
265 | EMU_SRC_MDOCK_SPDIF_LEFT1, | ||
266 | EMU_SRC_MDOCK_SPDIF_RIGHT1, | ||
267 | EMU_SRC_MDOCK_ADAT, | ||
268 | EMU_SRC_MDOCK_ADAT+1, | ||
269 | EMU_SRC_MDOCK_ADAT+2, | ||
270 | EMU_SRC_MDOCK_ADAT+3, | ||
271 | EMU_SRC_MDOCK_ADAT+4, | ||
272 | EMU_SRC_MDOCK_ADAT+5, | ||
273 | EMU_SRC_MDOCK_ADAT+6, | ||
274 | EMU_SRC_MDOCK_ADAT+7, | ||
275 | EMU_SRC_ALICE_EMU32A, | ||
276 | EMU_SRC_ALICE_EMU32A+1, | ||
277 | EMU_SRC_ALICE_EMU32A+2, | ||
278 | EMU_SRC_ALICE_EMU32A+3, | ||
279 | EMU_SRC_ALICE_EMU32A+4, | ||
280 | EMU_SRC_ALICE_EMU32A+5, | ||
281 | EMU_SRC_ALICE_EMU32A+6, | ||
282 | EMU_SRC_ALICE_EMU32A+7, | ||
283 | EMU_SRC_ALICE_EMU32A+8, | ||
284 | EMU_SRC_ALICE_EMU32A+9, | ||
285 | EMU_SRC_ALICE_EMU32A+0xa, | ||
286 | EMU_SRC_ALICE_EMU32A+0xb, | ||
287 | EMU_SRC_ALICE_EMU32A+0xc, | ||
288 | EMU_SRC_ALICE_EMU32A+0xd, | ||
289 | EMU_SRC_ALICE_EMU32A+0xe, | ||
290 | EMU_SRC_ALICE_EMU32A+0xf, | ||
291 | EMU_SRC_ALICE_EMU32B, | ||
292 | EMU_SRC_ALICE_EMU32B+1, | ||
293 | EMU_SRC_ALICE_EMU32B+2, | ||
294 | EMU_SRC_ALICE_EMU32B+3, | ||
295 | EMU_SRC_ALICE_EMU32B+4, | ||
296 | EMU_SRC_ALICE_EMU32B+5, | ||
297 | EMU_SRC_ALICE_EMU32B+6, | ||
298 | EMU_SRC_ALICE_EMU32B+7, | ||
299 | EMU_SRC_ALICE_EMU32B+8, | ||
300 | EMU_SRC_ALICE_EMU32B+9, | ||
301 | EMU_SRC_ALICE_EMU32B+0xa, | ||
302 | EMU_SRC_ALICE_EMU32B+0xb, | ||
303 | EMU_SRC_ALICE_EMU32B+0xc, | ||
304 | EMU_SRC_ALICE_EMU32B+0xd, | ||
305 | EMU_SRC_ALICE_EMU32B+0xe, | ||
306 | EMU_SRC_ALICE_EMU32B+0xf, | ||
307 | }; | ||
308 | |||
199 | /* | 309 | /* |
200 | * Data destinations - physical EMU outputs. | 310 | * Data destinations - physical EMU outputs. |
201 | * Each destination has an enum mixer control to choose a data source | 311 | * Each destination has an enum mixer control to choose a data source |
@@ -227,6 +337,28 @@ static unsigned int emu1010_output_dst[] = { | |||
227 | EMU_DST_HANA_ADAT+7, /* 23 */ | 337 | EMU_DST_HANA_ADAT+7, /* 23 */ |
228 | }; | 338 | }; |
229 | 339 | ||
340 | /* 1616(m) cardbus */ | ||
341 | static unsigned int emu1616_output_dst[] = { | ||
342 | EMU_DST_DOCK_DAC1_LEFT1, | ||
343 | EMU_DST_DOCK_DAC1_RIGHT1, | ||
344 | EMU_DST_DOCK_DAC2_LEFT1, | ||
345 | EMU_DST_DOCK_DAC2_RIGHT1, | ||
346 | EMU_DST_DOCK_DAC3_LEFT1, | ||
347 | EMU_DST_DOCK_DAC3_RIGHT1, | ||
348 | EMU_DST_MDOCK_SPDIF_LEFT1, | ||
349 | EMU_DST_MDOCK_SPDIF_RIGHT1, | ||
350 | EMU_DST_MDOCK_ADAT, | ||
351 | EMU_DST_MDOCK_ADAT+1, | ||
352 | EMU_DST_MDOCK_ADAT+2, | ||
353 | EMU_DST_MDOCK_ADAT+3, | ||
354 | EMU_DST_MDOCK_ADAT+4, | ||
355 | EMU_DST_MDOCK_ADAT+5, | ||
356 | EMU_DST_MDOCK_ADAT+6, | ||
357 | EMU_DST_MDOCK_ADAT+7, | ||
358 | EMU_DST_MANA_DAC_LEFT, | ||
359 | EMU_DST_MANA_DAC_RIGHT, | ||
360 | }; | ||
361 | |||
230 | /* | 362 | /* |
231 | * Data destinations - HANA outputs going to Alice2 (audigy) for | 363 | * Data destinations - HANA outputs going to Alice2 (audigy) for |
232 | * capture (EMU32 + I2S links) | 364 | * capture (EMU32 + I2S links) |
@@ -257,14 +389,26 @@ static unsigned int emu1010_input_dst[] = { | |||
257 | EMU_DST_ALICE_I2S2_RIGHT, | 389 | EMU_DST_ALICE_I2S2_RIGHT, |
258 | }; | 390 | }; |
259 | 391 | ||
260 | static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 392 | static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, |
393 | struct snd_ctl_elem_info *uinfo) | ||
261 | { | 394 | { |
395 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
396 | char **items; | ||
397 | |||
262 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 398 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
263 | uinfo->count = 1; | 399 | uinfo->count = 1; |
264 | uinfo->value.enumerated.items = 53; | 400 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
401 | uinfo->value.enumerated.items = 49; | ||
402 | items = emu1616_src_texts; | ||
403 | } else { | ||
404 | uinfo->value.enumerated.items = 53; | ||
405 | items = emu1010_src_texts; | ||
406 | } | ||
265 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | 407 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) |
266 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | 408 | uinfo->value.enumerated.item = |
267 | strcpy(uinfo->value.enumerated.name, emu1010_src_texts[uinfo->value.enumerated.item]); | 409 | uinfo->value.enumerated.items - 1; |
410 | strcpy(uinfo->value.enumerated.name, | ||
411 | items[uinfo->value.enumerated.item]); | ||
268 | return 0; | 412 | return 0; |
269 | } | 413 | } |
270 | 414 | ||
@@ -272,9 +416,14 @@ static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, | |||
272 | struct snd_ctl_elem_value *ucontrol) | 416 | struct snd_ctl_elem_value *ucontrol) |
273 | { | 417 | { |
274 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 418 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
275 | int channel; | 419 | unsigned int channel; |
276 | 420 | ||
277 | channel = (kcontrol->private_value) & 0xff; | 421 | channel = (kcontrol->private_value) & 0xff; |
422 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ | ||
423 | if (channel >= 24 || | ||
424 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
425 | channel >= 18)) | ||
426 | return -EINVAL; | ||
278 | ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; | 427 | ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; |
279 | return 0; | 428 | return 0; |
280 | } | 429 | } |
@@ -283,27 +432,42 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, | |||
283 | struct snd_ctl_elem_value *ucontrol) | 432 | struct snd_ctl_elem_value *ucontrol) |
284 | { | 433 | { |
285 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 434 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
286 | int change = 0; | ||
287 | unsigned int val; | 435 | unsigned int val; |
288 | int channel; | 436 | unsigned int channel; |
289 | 437 | ||
438 | val = ucontrol->value.enumerated.item[0]; | ||
439 | if (val >= 53 || | ||
440 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
441 | val >= 49)) | ||
442 | return -EINVAL; | ||
290 | channel = (kcontrol->private_value) & 0xff; | 443 | channel = (kcontrol->private_value) & 0xff; |
291 | if (emu->emu1010.output_source[channel] != ucontrol->value.enumerated.item[0]) { | 444 | /* Limit: emu1010_output_dst, emu->emu1010.output_source */ |
292 | val = emu->emu1010.output_source[channel] = ucontrol->value.enumerated.item[0]; | 445 | if (channel >= 24 || |
293 | change = 1; | 446 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && |
447 | channel >= 18)) | ||
448 | return -EINVAL; | ||
449 | if (emu->emu1010.output_source[channel] == val) | ||
450 | return 0; | ||
451 | emu->emu1010.output_source[channel] = val; | ||
452 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) | ||
453 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
454 | emu1616_output_dst[channel], emu1616_src_regs[val]); | ||
455 | else | ||
294 | snd_emu1010_fpga_link_dst_src_write(emu, | 456 | snd_emu1010_fpga_link_dst_src_write(emu, |
295 | emu1010_output_dst[channel], emu1010_src_regs[val]); | 457 | emu1010_output_dst[channel], emu1010_src_regs[val]); |
296 | } | 458 | return 1; |
297 | return change; | ||
298 | } | 459 | } |
299 | 460 | ||
300 | static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, | 461 | static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, |
301 | struct snd_ctl_elem_value *ucontrol) | 462 | struct snd_ctl_elem_value *ucontrol) |
302 | { | 463 | { |
303 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 464 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
304 | int channel; | 465 | unsigned int channel; |
305 | 466 | ||
306 | channel = (kcontrol->private_value) & 0xff; | 467 | channel = (kcontrol->private_value) & 0xff; |
468 | /* Limit: emu1010_input_dst, emu->emu1010.input_source */ | ||
469 | if (channel >= 22) | ||
470 | return -EINVAL; | ||
307 | ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; | 471 | ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; |
308 | return 0; | 472 | return 0; |
309 | } | 473 | } |
@@ -312,18 +476,28 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, | |||
312 | struct snd_ctl_elem_value *ucontrol) | 476 | struct snd_ctl_elem_value *ucontrol) |
313 | { | 477 | { |
314 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 478 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
315 | int change = 0; | ||
316 | unsigned int val; | 479 | unsigned int val; |
317 | int channel; | 480 | unsigned int channel; |
318 | 481 | ||
482 | val = ucontrol->value.enumerated.item[0]; | ||
483 | if (val >= 53 || | ||
484 | (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && | ||
485 | val >= 49)) | ||
486 | return -EINVAL; | ||
319 | channel = (kcontrol->private_value) & 0xff; | 487 | channel = (kcontrol->private_value) & 0xff; |
320 | if (emu->emu1010.input_source[channel] != ucontrol->value.enumerated.item[0]) { | 488 | /* Limit: emu1010_input_dst, emu->emu1010.input_source */ |
321 | val = emu->emu1010.input_source[channel] = ucontrol->value.enumerated.item[0]; | 489 | if (channel >= 22) |
322 | change = 1; | 490 | return -EINVAL; |
491 | if (emu->emu1010.input_source[channel] == val) | ||
492 | return 0; | ||
493 | emu->emu1010.input_source[channel] = val; | ||
494 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) | ||
495 | snd_emu1010_fpga_link_dst_src_write(emu, | ||
496 | emu1010_input_dst[channel], emu1616_src_regs[val]); | ||
497 | else | ||
323 | snd_emu1010_fpga_link_dst_src_write(emu, | 498 | snd_emu1010_fpga_link_dst_src_write(emu, |
324 | emu1010_input_dst[channel], emu1010_src_regs[val]); | 499 | emu1010_input_dst[channel], emu1010_src_regs[val]); |
325 | } | 500 | return 1; |
326 | return change; | ||
327 | } | 501 | } |
328 | 502 | ||
329 | #define EMU1010_SOURCE_OUTPUT(xname,chid) \ | 503 | #define EMU1010_SOURCE_OUTPUT(xname,chid) \ |
@@ -363,6 +537,30 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { | |||
363 | EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), | 537 | EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), |
364 | }; | 538 | }; |
365 | 539 | ||
540 | |||
541 | /* 1616(m) cardbus */ | ||
542 | static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { | ||
543 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), | ||
544 | EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), | ||
545 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), | ||
546 | EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), | ||
547 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), | ||
548 | EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), | ||
549 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), | ||
550 | EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), | ||
551 | EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), | ||
552 | EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), | ||
553 | EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), | ||
554 | EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), | ||
555 | EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), | ||
556 | EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), | ||
557 | EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), | ||
558 | EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), | ||
559 | EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), | ||
560 | EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), | ||
561 | }; | ||
562 | |||
563 | |||
366 | #define EMU1010_SOURCE_INPUT(xname,chid) \ | 564 | #define EMU1010_SOURCE_INPUT(xname,chid) \ |
367 | { \ | 565 | { \ |
368 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 566 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
@@ -533,6 +731,9 @@ static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, | |||
533 | int change = 0; | 731 | int change = 0; |
534 | 732 | ||
535 | val = ucontrol->value.enumerated.item[0] ; | 733 | val = ucontrol->value.enumerated.item[0] ; |
734 | /* Limit: uinfo->value.enumerated.items = 4; */ | ||
735 | if (val >= 4) | ||
736 | return -EINVAL; | ||
536 | change = (emu->emu1010.internal_clock != val); | 737 | change = (emu->emu1010.internal_clock != val); |
537 | if (change) { | 738 | if (change) { |
538 | emu->emu1010.internal_clock = val; | 739 | emu->emu1010.internal_clock = val; |
@@ -669,7 +870,11 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | |||
669 | * update the capture volume from the cached value | 870 | * update the capture volume from the cached value |
670 | * for the particular source. | 871 | * for the particular source. |
671 | */ | 872 | */ |
672 | source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ | 873 | source_id = ucontrol->value.enumerated.item[0]; |
874 | /* Limit: uinfo->value.enumerated.items = 2; */ | ||
875 | /* emu->i2c_capture_volume */ | ||
876 | if (source_id >= 2) | ||
877 | return -EINVAL; | ||
673 | change = (emu->i2c_capture_source != source_id); | 878 | change = (emu->i2c_capture_source != source_id); |
674 | if (change) { | 879 | if (change) { |
675 | snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | 880 | snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ |
@@ -720,9 +925,13 @@ static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, | |||
720 | struct snd_ctl_elem_value *ucontrol) | 925 | struct snd_ctl_elem_value *ucontrol) |
721 | { | 926 | { |
722 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 927 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
723 | int source_id; | 928 | unsigned int source_id; |
724 | 929 | ||
725 | source_id = kcontrol->private_value; | 930 | source_id = kcontrol->private_value; |
931 | /* Limit: emu->i2c_capture_volume */ | ||
932 | /* capture_source: uinfo->value.enumerated.items = 2 */ | ||
933 | if (source_id >= 2) | ||
934 | return -EINVAL; | ||
726 | 935 | ||
727 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; | 936 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; |
728 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; | 937 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; |
@@ -735,10 +944,14 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
735 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | 944 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
736 | unsigned int ogain; | 945 | unsigned int ogain; |
737 | unsigned int ngain; | 946 | unsigned int ngain; |
738 | int source_id; | 947 | unsigned int source_id; |
739 | int change = 0; | 948 | int change = 0; |
740 | 949 | ||
741 | source_id = kcontrol->private_value; | 950 | source_id = kcontrol->private_value; |
951 | /* Limit: emu->i2c_capture_volume */ | ||
952 | /* capture_source: uinfo->value.enumerated.items = 2 */ | ||
953 | if (source_id >= 2) | ||
954 | return -EINVAL; | ||
742 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | 955 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ |
743 | ngain = ucontrol->value.integer.value[0]; | 956 | ngain = ucontrol->value.integer.value[0]; |
744 | if (ngain > 0xff) | 957 | if (ngain > 0xff) |
@@ -746,7 +959,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
746 | if (ogain != ngain) { | 959 | if (ogain != ngain) { |
747 | if (emu->i2c_capture_source == source_id) | 960 | if (emu->i2c_capture_source == source_id) |
748 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | 961 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); |
749 | emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; | 962 | emu->i2c_capture_volume[source_id][0] = ngain; |
750 | change = 1; | 963 | change = 1; |
751 | } | 964 | } |
752 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | 965 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ |
@@ -756,7 +969,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | |||
756 | if (ogain != ngain) { | 969 | if (ogain != ngain) { |
757 | if (emu->i2c_capture_source == source_id) | 970 | if (emu->i2c_capture_source == source_id) |
758 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | 971 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); |
759 | emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; | 972 | emu->i2c_capture_volume[source_id][1] = ngain; |
760 | change = 1; | 973 | change = 1; |
761 | } | 974 | } |
762 | 975 | ||
@@ -877,6 +1090,9 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, | |||
877 | unsigned int val; | 1090 | unsigned int val; |
878 | unsigned long flags; | 1091 | unsigned long flags; |
879 | 1092 | ||
1093 | /* Limit: emu->spdif_bits */ | ||
1094 | if (idx >= 3) | ||
1095 | return -EINVAL; | ||
880 | val = (ucontrol->value.iec958.status[0] << 0) | | 1096 | val = (ucontrol->value.iec958.status[0] << 0) | |
881 | (ucontrol->value.iec958.status[1] << 8) | | 1097 | (ucontrol->value.iec958.status[1] << 8) | |
882 | (ucontrol->value.iec958.status[2] << 16) | | 1098 | (ucontrol->value.iec958.status[2] << 16) | |
@@ -1754,7 +1970,7 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1754 | return err; | 1970 | return err; |
1755 | } | 1971 | } |
1756 | 1972 | ||
1757 | if ( emu->card_capabilities->emu1010) { | 1973 | if (emu->card_capabilities->emu_model) { |
1758 | ; /* Disable the snd_audigy_spdif_shared_spdif */ | 1974 | ; /* Disable the snd_audigy_spdif_shared_spdif */ |
1759 | } else if (emu->audigy) { | 1975 | } else if (emu->audigy) { |
1760 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) | 1976 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) |
@@ -1779,30 +1995,73 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1779 | return err; | 1995 | return err; |
1780 | } | 1996 | } |
1781 | 1997 | ||
1782 | if ( emu->card_capabilities->emu1010) { | 1998 | if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { |
1999 | /* 1616(m) cardbus */ | ||
2000 | int i; | ||
2001 | |||
2002 | for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { | ||
2003 | err = snd_ctl_add(card, | ||
2004 | snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], | ||
2005 | emu)); | ||
2006 | if (err < 0) | ||
2007 | return err; | ||
2008 | } | ||
2009 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { | ||
2010 | err = snd_ctl_add(card, | ||
2011 | snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], | ||
2012 | emu)); | ||
2013 | if (err < 0) | ||
2014 | return err; | ||
2015 | } | ||
2016 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { | ||
2017 | err = snd_ctl_add(card, | ||
2018 | snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | ||
2019 | if (err < 0) | ||
2020 | return err; | ||
2021 | } | ||
2022 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { | ||
2023 | err = snd_ctl_add(card, | ||
2024 | snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | ||
2025 | if (err < 0) | ||
2026 | return err; | ||
2027 | } | ||
2028 | err = snd_ctl_add(card, | ||
2029 | snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | ||
2030 | if (err < 0) | ||
2031 | return err; | ||
2032 | |||
2033 | } else if (emu->card_capabilities->emu_model) { | ||
2034 | /* all other e-mu cards for now */ | ||
1783 | int i; | 2035 | int i; |
1784 | 2036 | ||
1785 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { | 2037 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { |
1786 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], emu)); | 2038 | err = snd_ctl_add(card, |
2039 | snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], | ||
2040 | emu)); | ||
1787 | if (err < 0) | 2041 | if (err < 0) |
1788 | return err; | 2042 | return err; |
1789 | } | 2043 | } |
1790 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { | 2044 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { |
1791 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], emu)); | 2045 | err = snd_ctl_add(card, |
2046 | snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], | ||
2047 | emu)); | ||
1792 | if (err < 0) | 2048 | if (err < 0) |
1793 | return err; | 2049 | return err; |
1794 | } | 2050 | } |
1795 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { | 2051 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { |
1796 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | 2052 | err = snd_ctl_add(card, |
2053 | snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); | ||
1797 | if (err < 0) | 2054 | if (err < 0) |
1798 | return err; | 2055 | return err; |
1799 | } | 2056 | } |
1800 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { | 2057 | for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { |
1801 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | 2058 | err = snd_ctl_add(card, |
2059 | snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); | ||
1802 | if (err < 0) | 2060 | if (err < 0) |
1803 | return err; | 2061 | return err; |
1804 | } | 2062 | } |
1805 | err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | 2063 | err = snd_ctl_add(card, |
2064 | snd_ctl_new1(&snd_emu1010_internal_clock, emu)); | ||
1806 | if (err < 0) | 2065 | if (err < 0) |
1807 | return err; | 2066 | return err; |
1808 | } | 2067 | } |
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index 04c7cf703531..c4d76d16661e 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | 22 | #include <linux/time.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <sound/core.h> | 24 | #include <sound/core.h> |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 5ce5befc701b..cf9276ddad42 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
@@ -358,7 +357,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, | |||
358 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); | 357 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); |
359 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); | 358 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); |
360 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); | 359 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); |
361 | if (emu->card_capabilities->emu1010) | 360 | if (emu->card_capabilities->emu_model) |
362 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | 361 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ |
363 | else | 362 | else |
364 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 363 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); |
@@ -701,7 +700,7 @@ static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct s | |||
701 | voice = evoice->number; | 700 | voice = evoice->number; |
702 | 701 | ||
703 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; | 702 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; |
704 | if (emu->card_capabilities->emu1010) | 703 | if (emu->card_capabilities->emu_model) |
705 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ | 704 | pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ |
706 | else | 705 | else |
707 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | 706 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); |
@@ -1232,7 +1231,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) | |||
1232 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | 1231 | runtime->hw.rates = SNDRV_PCM_RATE_48000; |
1233 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | 1232 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; |
1234 | spin_lock_irq(&emu->reg_lock); | 1233 | spin_lock_irq(&emu->reg_lock); |
1235 | if (emu->card_capabilities->emu1010) { | 1234 | if (emu->card_capabilities->emu_model) { |
1236 | /* Nb. of channels has been increased to 16 */ | 1235 | /* Nb. of channels has been increased to 16 */ |
1237 | /* TODO | 1236 | /* TODO |
1238 | * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | 1237 | * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE |
@@ -1791,7 +1790,7 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s | |||
1791 | /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ | 1790 | /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ |
1792 | if (emu->audigy) { | 1791 | if (emu->audigy) { |
1793 | emu->efx_voices_mask[0] = 0; | 1792 | emu->efx_voices_mask[0] = 0; |
1794 | if (emu->card_capabilities->emu1010) | 1793 | if (emu->card_capabilities->emu_model) |
1795 | /* Pavel Hofman - 32 voices will be used for | 1794 | /* Pavel Hofman - 32 voices will be used for |
1796 | * capture (write mode) - | 1795 | * capture (write mode) - |
1797 | * each bit = corresponding voice | 1796 | * each bit = corresponding voice |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index c3fb10e81c9e..f3caa3f890c6 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <sound/core.h> | 33 | #include <sound/core.h> |
@@ -245,7 +244,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, | |||
245 | unsigned long flags; | 244 | unsigned long flags; |
246 | u32 rate; | 245 | u32 rate; |
247 | 246 | ||
248 | if (emu->card_capabilities->emu1010) { | 247 | if (emu->card_capabilities->emu_model) { |
249 | spin_lock_irqsave(&emu->emu_lock, flags); | 248 | spin_lock_irqsave(&emu->emu_lock, flags); |
250 | snd_emu1010_fpga_read(emu, 0x38, &value); | 249 | snd_emu1010_fpga_read(emu, 0x38, &value); |
251 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 250 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
@@ -585,7 +584,7 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) | |||
585 | { | 584 | { |
586 | struct snd_info_entry *entry; | 585 | struct snd_info_entry *entry; |
587 | #ifdef CONFIG_SND_DEBUG | 586 | #ifdef CONFIG_SND_DEBUG |
588 | if (emu->card_capabilities->emu1010) { | 587 | if (emu->card_capabilities->emu_model) { |
589 | if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) | 588 | if (! snd_card_proc_new(emu->card, "emu1010_regs", &entry)) |
590 | snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); | 589 | snd_info_set_text_ops(entry, emu, snd_emu_proc_emu1010_reg_read); |
591 | } | 590 | } |
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 6702c15fefa3..b5a802bdeb7c 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
@@ -71,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i | |||
71 | unsigned long flags; | 70 | unsigned long flags; |
72 | unsigned int mask; | 71 | unsigned int mask; |
73 | 72 | ||
73 | if (!emu) { | ||
74 | snd_printk(KERN_ERR "ptr_write: emu is null!\n"); | ||
75 | dump_stack(); | ||
76 | return; | ||
77 | } | ||
74 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; | 78 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; |
75 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); | 79 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); |
76 | 80 | ||
@@ -135,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
135 | unsigned int reset, set; | 139 | unsigned int reset, set; |
136 | unsigned int reg, tmp; | 140 | unsigned int reg, tmp; |
137 | int n, result; | 141 | int n, result; |
142 | int err = 0; | ||
143 | |||
144 | /* This function is not re-entrant, so protect against it. */ | ||
145 | spin_lock(&emu->spi_lock); | ||
138 | if (emu->card_capabilities->ca0108_chip) | 146 | if (emu->card_capabilities->ca0108_chip) |
139 | reg = 0x3c; /* PTR20, reg 0x3c */ | 147 | reg = 0x3c; /* PTR20, reg 0x3c */ |
140 | else { | 148 | else { |
141 | /* For other chip types the SPI register | 149 | /* For other chip types the SPI register |
142 | * is currently unknown. */ | 150 | * is currently unknown. */ |
143 | return 1; | 151 | err = 1; |
152 | goto spi_write_exit; | ||
153 | } | ||
154 | if (data > 0xffff) { | ||
155 | /* Only 16bit values allowed */ | ||
156 | err = 1; | ||
157 | goto spi_write_exit; | ||
144 | } | 158 | } |
145 | if (data > 0xffff) /* Only 16bit values allowed */ | ||
146 | return 1; | ||
147 | 159 | ||
148 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); | 160 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); |
149 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ | 161 | reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ |
@@ -161,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
161 | break; | 173 | break; |
162 | } | 174 | } |
163 | } | 175 | } |
164 | if (result) /* Timed out */ | 176 | if (result) { |
165 | return 1; | 177 | /* Timed out */ |
178 | err = 1; | ||
179 | goto spi_write_exit; | ||
180 | } | ||
166 | snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); | 181 | snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); |
167 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ | 182 | tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ |
168 | return 0; | 183 | err = 0; |
184 | spi_write_exit: | ||
185 | spin_unlock(&emu->spi_lock); | ||
186 | return err; | ||
169 | } | 187 | } |
170 | 188 | ||
171 | /* The ADC does not support i2c read, so only write is implemented */ | 189 | /* The ADC does not support i2c read, so only write is implemented */ |
@@ -177,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
177 | int timeout = 0; | 195 | int timeout = 0; |
178 | int status; | 196 | int status; |
179 | int retry; | 197 | int retry; |
198 | int err = 0; | ||
199 | |||
180 | if ((reg > 0x7f) || (value > 0x1ff)) { | 200 | if ((reg > 0x7f) || (value > 0x1ff)) { |
181 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | 201 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); |
182 | return -EINVAL; | 202 | return -EINVAL; |
183 | } | 203 | } |
184 | 204 | ||
205 | /* This function is not re-entrant, so protect against it. */ | ||
206 | spin_lock(&emu->i2c_lock); | ||
207 | |||
185 | tmp = reg << 25 | value << 16; | 208 | tmp = reg << 25 | value << 16; |
186 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
187 | /* Not sure what this I2C channel controls. */ | ||
188 | /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ | ||
189 | 209 | ||
190 | /* This controls the I2C connected to the WM8775 ADC Codec */ | 210 | /* This controls the I2C connected to the WM8775 ADC Codec */ |
191 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); | 211 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); |
@@ -193,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
193 | 213 | ||
194 | for (retry = 0; retry < 10; retry++) { | 214 | for (retry = 0; retry < 10; retry++) { |
195 | /* Send the data to i2c */ | 215 | /* Send the data to i2c */ |
196 | //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); | ||
197 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
198 | tmp = 0; | 216 | tmp = 0; |
199 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | 217 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); |
200 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); | 218 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); |
201 | 219 | ||
202 | /* Wait till the transaction ends */ | 220 | /* Wait till the transaction ends */ |
203 | while (1) { | 221 | while (1) { |
204 | udelay(10); | 222 | mdelay(1); |
205 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); | 223 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); |
206 | // snd_printk("I2C:status=0x%x\n", status); | ||
207 | timeout++; | 224 | timeout++; |
208 | if ((status & I2C_A_ADC_START) == 0) | 225 | if ((status & I2C_A_ADC_START) == 0) |
209 | break; | 226 | break; |
@@ -220,19 +237,26 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | |||
220 | 237 | ||
221 | if (retry == 10) { | 238 | if (retry == 10) { |
222 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | 239 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); |
223 | return -EINVAL; | 240 | snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n", |
241 | status, reg, value); | ||
242 | /* dump_stack(); */ | ||
243 | err = -EINVAL; | ||
224 | } | 244 | } |
225 | 245 | ||
226 | return 0; | 246 | spin_unlock(&emu->i2c_lock); |
247 | return err; | ||
227 | } | 248 | } |
228 | 249 | ||
229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | 250 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) |
230 | { | 251 | { |
252 | unsigned long flags; | ||
253 | |||
231 | if (reg > 0x3f) | 254 | if (reg > 0x3f) |
232 | return 1; | 255 | return 1; |
233 | reg += 0x40; /* 0x40 upwards are registers. */ | 256 | reg += 0x40; /* 0x40 upwards are registers. */ |
234 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ | 257 | if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ |
235 | return 1; | 258 | return 1; |
259 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
236 | outl(reg, emu->port + A_IOCFG); | 260 | outl(reg, emu->port + A_IOCFG); |
237 | udelay(10); | 261 | udelay(10); |
238 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 262 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
@@ -240,20 +264,24 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | |||
240 | outl(value, emu->port + A_IOCFG); | 264 | outl(value, emu->port + A_IOCFG); |
241 | udelay(10); | 265 | udelay(10); |
242 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 266 | outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
267 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
243 | 268 | ||
244 | return 0; | 269 | return 0; |
245 | } | 270 | } |
246 | 271 | ||
247 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) | 272 | int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) |
248 | { | 273 | { |
274 | unsigned long flags; | ||
249 | if (reg > 0x3f) | 275 | if (reg > 0x3f) |
250 | return 1; | 276 | return 1; |
251 | reg += 0x40; /* 0x40 upwards are registers. */ | 277 | reg += 0x40; /* 0x40 upwards are registers. */ |
278 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
252 | outl(reg, emu->port + A_IOCFG); | 279 | outl(reg, emu->port + A_IOCFG); |
253 | udelay(10); | 280 | udelay(10); |
254 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ | 281 | outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ |
255 | udelay(10); | 282 | udelay(10); |
256 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); | 283 | *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); |
284 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
257 | 285 | ||
258 | return 0; | 286 | return 0; |
259 | } | 287 | } |
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 3c114b45e0b2..30bfed6f8339 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
@@ -35,9 +34,10 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) | |||
35 | struct snd_emu10k1 *emu = dev_id; | 34 | struct snd_emu10k1 *emu = dev_id; |
36 | unsigned int status, status2, orig_status, orig_status2; | 35 | unsigned int status, status2, orig_status, orig_status2; |
37 | int handled = 0; | 36 | int handled = 0; |
37 | int timeout = 0; | ||
38 | 38 | ||
39 | while ((status = inl(emu->port + IPR)) != 0) { | 39 | while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) { |
40 | //snd_printk(KERN_INFO "emu10k1 irq - status = 0x%x\n", status); | 40 | timeout++; |
41 | orig_status = status; | 41 | orig_status = status; |
42 | handled = 1; | 42 | handled = 1; |
43 | if ((status & 0xffffffff) == 0xffffffff) { | 43 | if ((status & 0xffffffff) == 0xffffffff) { |
@@ -201,5 +201,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) | |||
201 | } | 201 | } |
202 | outl(orig_status, emu->port + IPR); /* ack all */ | 202 | outl(orig_status, emu->port + IPR); /* ack all */ |
203 | } | 203 | } |
204 | if (timeout == 1000) | ||
205 | snd_printk(KERN_INFO "emu10k1 irq routine failure\n"); | ||
206 | |||
204 | return IRQ_RETVAL(handled); | 207 | return IRQ_RETVAL(handled); |
205 | } | 208 | } |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 48097c6bb15c..916c1dbcd53c 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
26 | #include <linux/time.h> | 25 | #include <linux/time.h> |
27 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d619a3842cdd..749a21b6bd06 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -87,7 +87,6 @@ | |||
87 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 87 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
88 | * | 88 | * |
89 | */ | 89 | */ |
90 | #include <sound/driver.h> | ||
91 | #include <linux/delay.h> | 90 | #include <linux/delay.h> |
92 | #include <linux/init.h> | 91 | #include <linux/init.h> |
93 | #include <linux/interrupt.h> | 92 | #include <linux/interrupt.h> |
@@ -742,6 +741,8 @@ static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol, | |||
742 | u32 source; | 741 | u32 source; |
743 | 742 | ||
744 | val = ucontrol->value.enumerated.item[0] ; | 743 | val = ucontrol->value.enumerated.item[0] ; |
744 | if (val > 7) | ||
745 | return -EINVAL; | ||
745 | change = (emu->p16v_capture_source != val); | 746 | change = (emu->p16v_capture_source != val); |
746 | if (change) { | 747 | if (change) { |
747 | emu->p16v_capture_source = val; | 748 | emu->p16v_capture_source = val; |
@@ -784,6 +785,8 @@ static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, | |||
784 | u32 tmp; | 785 | u32 tmp; |
785 | 786 | ||
786 | val = ucontrol->value.enumerated.item[0] ; | 787 | val = ucontrol->value.enumerated.item[0] ; |
788 | if (val > 3) | ||
789 | return -EINVAL; | ||
787 | change = (emu->p16v_capture_channel != val); | 790 | change = (emu->p16v_capture_channel != val); |
788 | if (change) { | 791 | if (change) { |
789 | emu->p16v_capture_channel = val; | 792 | emu->p16v_capture_channel = val; |
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 6295b2dca785..72321e946ccc 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c | |||
@@ -25,7 +25,6 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
30 | #include <sound/core.h> | 29 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 30 | #include <sound/emu10k1.h> |
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 04fa8492abb0..958cb2a65a4e 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c | |||
@@ -28,7 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <sound/driver.h> | ||
32 | #include <linux/time.h> | 31 | #include <linux/time.h> |
33 | #include <sound/core.h> | 32 | #include <sound/core.h> |
34 | #include <sound/emu10k1.h> | 33 | #include <sound/emu10k1.h> |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index b958f869cb13..72d85a5ae6a0 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * by Kurt J. Bosch | 26 | * by Kurt J. Bosch |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <asm/io.h> | 29 | #include <asm/io.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb25abe68a02..1a314fa99c45 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -47,7 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/init.h> | 50 | #include <linux/init.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
53 | #include <linux/pci.h> | 52 | #include <linux/pci.h> |
@@ -227,6 +226,7 @@ struct es1938 { | |||
227 | unsigned int dma2_start; | 226 | unsigned int dma2_start; |
228 | unsigned int dma1_shift; | 227 | unsigned int dma1_shift; |
229 | unsigned int dma2_shift; | 228 | unsigned int dma2_shift; |
229 | unsigned int last_capture_dmaaddr; | ||
230 | unsigned int active; | 230 | unsigned int active; |
231 | 231 | ||
232 | spinlock_t reg_lock; | 232 | spinlock_t reg_lock; |
@@ -529,6 +529,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip) | |||
529 | outb(1, SLDM_REG(chip, DMAMASK)); | 529 | outb(1, SLDM_REG(chip, DMAMASK)); |
530 | outb(0x14, SLDM_REG(chip, DMAMODE)); | 530 | outb(0x14, SLDM_REG(chip, DMAMODE)); |
531 | outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); | 531 | outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); |
532 | chip->last_capture_dmaaddr = chip->dma1_start; | ||
532 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); | 533 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); |
533 | /* 3. Unmask DMA */ | 534 | /* 3. Unmask DMA */ |
534 | outb(0, SLDM_REG(chip, DMAMASK)); | 535 | outb(0, SLDM_REG(chip, DMAMASK)); |
@@ -770,19 +771,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream) | |||
770 | return -EINVAL; | 771 | return -EINVAL; |
771 | } | 772 | } |
772 | 773 | ||
774 | /* during the incrementing of dma counters the DMA register reads sometimes | ||
775 | returns garbage. To ensure a valid hw pointer, the following checks which | ||
776 | should be very unlikely to fail are used: | ||
777 | - is the current DMA address in the valid DMA range ? | ||
778 | - is the sum of DMA address and DMA counter pointing to the last DMA byte ? | ||
779 | One can argue this could differ by one byte depending on which register is | ||
780 | updated first, so the implementation below allows for that. | ||
781 | */ | ||
773 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) | 782 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) |
774 | { | 783 | { |
775 | struct es1938 *chip = snd_pcm_substream_chip(substream); | 784 | struct es1938 *chip = snd_pcm_substream_chip(substream); |
776 | size_t ptr; | 785 | size_t ptr; |
786 | #if 0 | ||
777 | size_t old, new; | 787 | size_t old, new; |
778 | #if 1 | ||
779 | /* This stuff is *needed*, don't ask why - AB */ | 788 | /* This stuff is *needed*, don't ask why - AB */ |
780 | old = inw(SLDM_REG(chip, DMACOUNT)); | 789 | old = inw(SLDM_REG(chip, DMACOUNT)); |
781 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) | 790 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) |
782 | old = new; | 791 | old = new; |
783 | ptr = chip->dma1_size - 1 - new; | 792 | ptr = chip->dma1_size - 1 - new; |
784 | #else | 793 | #else |
785 | ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start; | 794 | size_t count; |
795 | unsigned int diff; | ||
796 | |||
797 | ptr = inl(SLDM_REG(chip, DMAADDR)); | ||
798 | count = inw(SLDM_REG(chip, DMACOUNT)); | ||
799 | diff = chip->dma1_start + chip->dma1_size - ptr - count; | ||
800 | |||
801 | if (diff > 3 || ptr < chip->dma1_start | ||
802 | || ptr >= chip->dma1_start+chip->dma1_size) | ||
803 | ptr = chip->last_capture_dmaaddr; /* bad, use last saved */ | ||
804 | else | ||
805 | chip->last_capture_dmaaddr = ptr; /* good, remember it */ | ||
806 | |||
807 | ptr -= chip->dma1_start; | ||
786 | #endif | 808 | #endif |
787 | return ptr >> chip->dma1_shift; | 809 | return ptr >> chip->dma1_shift; |
788 | } | 810 | } |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index d69b11d1f993..25ccfce45759 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -94,7 +94,6 @@ | |||
94 | * places. | 94 | * places. |
95 | */ | 95 | */ |
96 | 96 | ||
97 | #include <sound/driver.h> | ||
98 | #include <asm/io.h> | 97 | #include <asm/io.h> |
99 | #include <linux/delay.h> | 98 | #include <linux/delay.h> |
100 | #include <linux/interrupt.h> | 99 | #include <linux/interrupt.h> |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 9939109f05a2..4c300e6149fc 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -979,6 +978,27 @@ static unsigned int snd_fm801_tea575x_64pcr_read(struct snd_tea575x *tea) | |||
979 | return val; | 978 | return val; |
980 | } | 979 | } |
981 | 980 | ||
981 | static void snd_fm801_tea575x_64pcr_mute(struct snd_tea575x *tea, | ||
982 | unsigned int mute) | ||
983 | { | ||
984 | struct fm801 *chip = tea->private_data; | ||
985 | unsigned short reg; | ||
986 | |||
987 | spin_lock_irq(&chip->reg_lock); | ||
988 | |||
989 | reg = inw(FM801_REG(chip, GPIO_CTRL)); | ||
990 | if (mute) | ||
991 | /* 0xf800 (mute) */ | ||
992 | reg &= ~FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); | ||
993 | else | ||
994 | /* 0xf802 (unmute) */ | ||
995 | reg |= FM801_GPIO_GP(TEA_64PCR_WRITE_ENABLE); | ||
996 | outw(reg, FM801_REG(chip, GPIO_CTRL)); | ||
997 | udelay(1); | ||
998 | |||
999 | spin_unlock_irq(&chip->reg_lock); | ||
1000 | } | ||
1001 | |||
982 | static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { | 1002 | static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { |
983 | { | 1003 | { |
984 | /* 1 = MediaForte 256-PCS */ | 1004 | /* 1 = MediaForte 256-PCS */ |
@@ -994,6 +1014,7 @@ static struct snd_tea575x_ops snd_fm801_tea_ops[3] = { | |||
994 | /* 3 = MediaForte 64-PCR */ | 1014 | /* 3 = MediaForte 64-PCR */ |
995 | .write = snd_fm801_tea575x_64pcr_write, | 1015 | .write = snd_fm801_tea575x_64pcr_write, |
996 | .read = snd_fm801_tea575x_64pcr_read, | 1016 | .read = snd_fm801_tea575x_64pcr_read, |
1017 | .mute = snd_fm801_tea575x_64pcr_mute, | ||
997 | } | 1018 | } |
998 | }; | 1019 | }; |
999 | #endif | 1020 | #endif |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index ab0c726d648e..9e0d8a1268aa 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -2,7 +2,7 @@ snd-hda-intel-y := hda_intel.o | |||
2 | # since snd-hda-intel is the only driver using hda-codec, | 2 | # since snd-hda-intel is the only driver using hda-codec, |
3 | # merge it into a single module although it was originally | 3 | # merge it into a single module although it was originally |
4 | # designed to be individual modules | 4 | # designed to be individual modules |
5 | snd-hda-intel-y += hda_codec.o | 5 | snd-hda-intel-y += hda_codec.o vmaster.o |
6 | snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o | 6 | snd-hda-intel-$(CONFIG_PROC_FS) += hda_proc.o |
7 | snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o | 7 | snd-hda-intel-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o |
8 | snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o | 8 | snd-hda-intel-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ad4cb38109fc..26812dc2b7f2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -55,6 +54,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { | |||
55 | { 0x10ec, "Realtek" }, | 54 | { 0x10ec, "Realtek" }, |
56 | { 0x1057, "Motorola" }, | 55 | { 0x1057, "Motorola" }, |
57 | { 0x1106, "VIA" }, | 56 | { 0x1106, "VIA" }, |
57 | { 0x111d, "IDT" }, | ||
58 | { 0x11d4, "Analog Devices" }, | 58 | { 0x11d4, "Analog Devices" }, |
59 | { 0x13f6, "C-Media" }, | 59 | { 0x13f6, "C-Media" }, |
60 | { 0x14f1, "Conexant" }, | 60 | { 0x14f1, "Conexant" }, |
@@ -429,6 +429,10 @@ find_codec_preset(struct hda_codec *codec) | |||
429 | for (tbl = hda_preset_tables; *tbl; tbl++) { | 429 | for (tbl = hda_preset_tables; *tbl; tbl++) { |
430 | for (preset = *tbl; preset->id; preset++) { | 430 | for (preset = *tbl; preset->id; preset++) { |
431 | u32 mask = preset->mask; | 431 | u32 mask = preset->mask; |
432 | if (preset->afg && preset->afg != codec->afg) | ||
433 | continue; | ||
434 | if (preset->mfg && preset->mfg != codec->mfg) | ||
435 | continue; | ||
432 | if (!mask) | 436 | if (!mask) |
433 | mask = ~0; | 437 | mask = ~0; |
434 | if (preset->id == (codec->vendor_id & mask) && | 438 | if (preset->id == (codec->vendor_id & mask) && |
@@ -765,7 +769,7 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key) | |||
765 | /* | 769 | /* |
766 | * query AMP capabilities for the given widget and direction | 770 | * query AMP capabilities for the given widget and direction |
767 | */ | 771 | */ |
768 | static u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) | 772 | u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) |
769 | { | 773 | { |
770 | struct hda_amp_info *info; | 774 | struct hda_amp_info *info; |
771 | 775 | ||
@@ -933,7 +937,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, | |||
933 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | 937 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; |
934 | if (!caps) { | 938 | if (!caps) { |
935 | printk(KERN_WARNING "hda_codec: " | 939 | printk(KERN_WARNING "hda_codec: " |
936 | "num_steps = 0 for NID=0x%x\n", nid); | 940 | "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, |
941 | kcontrol->id.name); | ||
937 | return -EINVAL; | 942 | return -EINVAL; |
938 | } | 943 | } |
939 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 944 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
@@ -1012,6 +1017,66 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
1012 | return 0; | 1017 | return 0; |
1013 | } | 1018 | } |
1014 | 1019 | ||
1020 | /* | ||
1021 | * set (static) TLV for virtual master volume; recalculated as max 0dB | ||
1022 | */ | ||
1023 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
1024 | unsigned int *tlv) | ||
1025 | { | ||
1026 | u32 caps; | ||
1027 | int nums, step; | ||
1028 | |||
1029 | caps = query_amp_caps(codec, nid, dir); | ||
1030 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
1031 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | ||
1032 | step = (step + 1) * 25; | ||
1033 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | ||
1034 | tlv[1] = 2 * sizeof(unsigned int); | ||
1035 | tlv[2] = -nums * step; | ||
1036 | tlv[3] = step; | ||
1037 | } | ||
1038 | |||
1039 | /* find a mixer control element with the given name */ | ||
1040 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
1041 | const char *name) | ||
1042 | { | ||
1043 | struct snd_ctl_elem_id id; | ||
1044 | memset(&id, 0, sizeof(id)); | ||
1045 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1046 | strcpy(id.name, name); | ||
1047 | return snd_ctl_find_id(codec->bus->card, &id); | ||
1048 | } | ||
1049 | |||
1050 | /* create a virtual master control and add slaves */ | ||
1051 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
1052 | unsigned int *tlv, const char **slaves) | ||
1053 | { | ||
1054 | struct snd_kcontrol *kctl; | ||
1055 | const char **s; | ||
1056 | int err; | ||
1057 | |||
1058 | kctl = snd_ctl_make_virtual_master(name, tlv); | ||
1059 | if (!kctl) | ||
1060 | return -ENOMEM; | ||
1061 | err = snd_ctl_add(codec->bus->card, kctl); | ||
1062 | if (err < 0) | ||
1063 | return err; | ||
1064 | |||
1065 | for (s = slaves; *s; s++) { | ||
1066 | struct snd_kcontrol *sctl; | ||
1067 | |||
1068 | sctl = snd_hda_find_mixer_ctl(codec, *s); | ||
1069 | if (!sctl) { | ||
1070 | snd_printdd("Cannot find slave %s, skipped\n", *s); | ||
1071 | continue; | ||
1072 | } | ||
1073 | err = snd_ctl_add_slave(kctl, sctl); | ||
1074 | if (err < 0) | ||
1075 | return err; | ||
1076 | } | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1015 | /* switch */ | 1080 | /* switch */ |
1016 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, | 1081 | int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, |
1017 | struct snd_ctl_elem_info *uinfo) | 1082 | struct snd_ctl_elem_info *uinfo) |
@@ -1434,7 +1499,8 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
1434 | return err; | 1499 | return err; |
1435 | } | 1500 | } |
1436 | codec->spdif_ctls = | 1501 | codec->spdif_ctls = |
1437 | snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | 1502 | snd_hda_codec_read(codec, nid, 0, |
1503 | AC_VERB_GET_DIGI_CONVERT_1, 0); | ||
1438 | codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); | 1504 | codec->spdif_status = convert_to_spdif_status(codec->spdif_ctls); |
1439 | return 0; | 1505 | return 0; |
1440 | } | 1506 | } |
@@ -1481,7 +1547,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, | |||
1481 | unsigned short val; | 1547 | unsigned short val; |
1482 | unsigned int sbits; | 1548 | unsigned int sbits; |
1483 | 1549 | ||
1484 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0); | 1550 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0); |
1485 | sbits = convert_to_spdif_status(val); | 1551 | sbits = convert_to_spdif_status(val); |
1486 | ucontrol->value.iec958.status[0] = sbits; | 1552 | ucontrol->value.iec958.status[0] = sbits; |
1487 | ucontrol->value.iec958.status[1] = sbits >> 8; | 1553 | ucontrol->value.iec958.status[1] = sbits >> 8; |
@@ -1532,7 +1598,8 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
1532 | return err; | 1598 | return err; |
1533 | } | 1599 | } |
1534 | codec->spdif_in_enable = | 1600 | codec->spdif_in_enable = |
1535 | snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DIGI_CONVERT, 0) & | 1601 | snd_hda_codec_read(codec, nid, 0, |
1602 | AC_VERB_GET_DIGI_CONVERT_1, 0) & | ||
1536 | AC_DIG1_ENABLE; | 1603 | AC_DIG1_ENABLE; |
1537 | return 0; | 1604 | return 0; |
1538 | } | 1605 | } |
@@ -1622,22 +1689,30 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
1622 | 1689 | ||
1623 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, | 1690 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, |
1624 | power_state); | 1691 | power_state); |
1692 | msleep(10); /* partial workaround for "azx_get_response timeout" */ | ||
1625 | 1693 | ||
1626 | nid = codec->start_nid; | 1694 | nid = codec->start_nid; |
1627 | for (i = 0; i < codec->num_nodes; i++, nid++) { | 1695 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
1628 | if (get_wcaps(codec, nid) & AC_WCAP_POWER) { | 1696 | unsigned int wcaps = get_wcaps(codec, nid); |
1629 | unsigned int pincap; | 1697 | if (wcaps & AC_WCAP_POWER) { |
1630 | /* | 1698 | unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> |
1631 | * don't power down the widget if it controls eapd | 1699 | AC_WCAP_TYPE_SHIFT; |
1632 | * and EAPD_BTLENABLE is set. | 1700 | if (wid_type == AC_WID_PIN) { |
1633 | */ | 1701 | unsigned int pincap; |
1634 | pincap = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 1702 | /* |
1635 | if (pincap & AC_PINCAP_EAPD) { | 1703 | * don't power down the widget if it controls |
1636 | int eapd = snd_hda_codec_read(codec, nid, | 1704 | * eapd and EAPD_BTLENABLE is set. |
1637 | 0, AC_VERB_GET_EAPD_BTLENABLE, 0); | 1705 | */ |
1638 | eapd &= 0x02; | 1706 | pincap = snd_hda_param_read(codec, nid, |
1639 | if (power_state == AC_PWRST_D3 && eapd) | 1707 | AC_PAR_PIN_CAP); |
1640 | continue; | 1708 | if (pincap & AC_PINCAP_EAPD) { |
1709 | int eapd = snd_hda_codec_read(codec, | ||
1710 | nid, 0, | ||
1711 | AC_VERB_GET_EAPD_BTLENABLE, 0); | ||
1712 | eapd &= 0x02; | ||
1713 | if (power_state == AC_PWRST_D3 && eapd) | ||
1714 | continue; | ||
1715 | } | ||
1641 | } | 1716 | } |
1642 | snd_hda_codec_write(codec, nid, 0, | 1717 | snd_hda_codec_write(codec, nid, 0, |
1643 | AC_VERB_SET_POWER_STATE, | 1718 | AC_VERB_SET_POWER_STATE, |
@@ -2329,7 +2404,8 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, | |||
2329 | unsigned int mode; | 2404 | unsigned int mode; |
2330 | 2405 | ||
2331 | mode = ucontrol->value.enumerated.item[0]; | 2406 | mode = ucontrol->value.enumerated.item[0]; |
2332 | snd_assert(mode < num_chmodes, return -EINVAL); | 2407 | if (mode >= num_chmodes) |
2408 | return -EINVAL; | ||
2333 | if (*max_channelsp == chmode[mode].channels) | 2409 | if (*max_channelsp == chmode[mode].channels) |
2334 | return 0; | 2410 | return 0; |
2335 | /* change the current channel setting */ | 2411 | /* change the current channel setting */ |
@@ -2485,13 +2561,14 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | |||
2485 | /* front */ | 2561 | /* front */ |
2486 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, | 2562 | snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, |
2487 | 0, format); | 2563 | 0, format); |
2488 | if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) | 2564 | if (!mout->no_share_stream && |
2565 | mout->hp_nid && mout->hp_nid != nids[HDA_FRONT]) | ||
2489 | /* headphone out will just decode front left/right (stereo) */ | 2566 | /* headphone out will just decode front left/right (stereo) */ |
2490 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, | 2567 | snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, |
2491 | 0, format); | 2568 | 0, format); |
2492 | /* extra outputs copied from front */ | 2569 | /* extra outputs copied from front */ |
2493 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) | 2570 | for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) |
2494 | if (mout->extra_out_nid[i]) | 2571 | if (!mout->no_share_stream && mout->extra_out_nid[i]) |
2495 | snd_hda_codec_setup_stream(codec, | 2572 | snd_hda_codec_setup_stream(codec, |
2496 | mout->extra_out_nid[i], | 2573 | mout->extra_out_nid[i], |
2497 | stream_tag, 0, format); | 2574 | stream_tag, 0, format); |
@@ -2501,7 +2578,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | |||
2501 | if (chs >= (i + 1) * 2) /* independent out */ | 2578 | if (chs >= (i + 1) * 2) /* independent out */ |
2502 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | 2579 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, |
2503 | i * 2, format); | 2580 | i * 2, format); |
2504 | else /* copy front */ | 2581 | else if (!mout->no_share_stream) /* copy front */ |
2505 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, | 2582 | snd_hda_codec_setup_stream(codec, nids[i], stream_tag, |
2506 | 0, format); | 2583 | 0, format); |
2507 | } | 2584 | } |
@@ -2594,20 +2671,21 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2594 | struct auto_pin_cfg *cfg, | 2671 | struct auto_pin_cfg *cfg, |
2595 | hda_nid_t *ignore_nids) | 2672 | hda_nid_t *ignore_nids) |
2596 | { | 2673 | { |
2597 | hda_nid_t nid, nid_start; | 2674 | hda_nid_t nid, end_nid; |
2598 | int nodes; | ||
2599 | short seq, assoc_line_out, assoc_speaker; | 2675 | short seq, assoc_line_out, assoc_speaker; |
2600 | short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; | 2676 | short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; |
2601 | short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; | 2677 | short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; |
2678 | short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; | ||
2602 | 2679 | ||
2603 | memset(cfg, 0, sizeof(*cfg)); | 2680 | memset(cfg, 0, sizeof(*cfg)); |
2604 | 2681 | ||
2605 | memset(sequences_line_out, 0, sizeof(sequences_line_out)); | 2682 | memset(sequences_line_out, 0, sizeof(sequences_line_out)); |
2606 | memset(sequences_speaker, 0, sizeof(sequences_speaker)); | 2683 | memset(sequences_speaker, 0, sizeof(sequences_speaker)); |
2684 | memset(sequences_hp, 0, sizeof(sequences_hp)); | ||
2607 | assoc_line_out = assoc_speaker = 0; | 2685 | assoc_line_out = assoc_speaker = 0; |
2608 | 2686 | ||
2609 | nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start); | 2687 | end_nid = codec->start_nid + codec->num_nodes; |
2610 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | 2688 | for (nid = codec->start_nid; nid < end_nid; nid++) { |
2611 | unsigned int wid_caps = get_wcaps(codec, nid); | 2689 | unsigned int wid_caps = get_wcaps(codec, nid); |
2612 | unsigned int wid_type = | 2690 | unsigned int wid_type = |
2613 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2691 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
@@ -2630,6 +2708,10 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2630 | case AC_JACK_LINE_OUT: | 2708 | case AC_JACK_LINE_OUT: |
2631 | seq = get_defcfg_sequence(def_conf); | 2709 | seq = get_defcfg_sequence(def_conf); |
2632 | assoc = get_defcfg_association(def_conf); | 2710 | assoc = get_defcfg_association(def_conf); |
2711 | |||
2712 | if (!(wid_caps & AC_WCAP_STEREO)) | ||
2713 | if (!cfg->mono_out_pin) | ||
2714 | cfg->mono_out_pin = nid; | ||
2633 | if (!assoc) | 2715 | if (!assoc) |
2634 | continue; | 2716 | continue; |
2635 | if (!assoc_line_out) | 2717 | if (!assoc_line_out) |
@@ -2658,9 +2740,12 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2658 | cfg->speaker_outs++; | 2740 | cfg->speaker_outs++; |
2659 | break; | 2741 | break; |
2660 | case AC_JACK_HP_OUT: | 2742 | case AC_JACK_HP_OUT: |
2743 | seq = get_defcfg_sequence(def_conf); | ||
2744 | assoc = get_defcfg_association(def_conf); | ||
2661 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) | 2745 | if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) |
2662 | continue; | 2746 | continue; |
2663 | cfg->hp_pins[cfg->hp_outs] = nid; | 2747 | cfg->hp_pins[cfg->hp_outs] = nid; |
2748 | sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; | ||
2664 | cfg->hp_outs++; | 2749 | cfg->hp_outs++; |
2665 | break; | 2750 | break; |
2666 | case AC_JACK_MIC_IN: { | 2751 | case AC_JACK_MIC_IN: { |
@@ -2704,7 +2789,24 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2704 | cfg->line_outs); | 2789 | cfg->line_outs); |
2705 | sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, | 2790 | sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, |
2706 | cfg->speaker_outs); | 2791 | cfg->speaker_outs); |
2792 | sort_pins_by_sequence(cfg->hp_pins, sequences_hp, | ||
2793 | cfg->hp_outs); | ||
2707 | 2794 | ||
2795 | /* if we have only one mic, make it AUTO_PIN_MIC */ | ||
2796 | if (!cfg->input_pins[AUTO_PIN_MIC] && | ||
2797 | cfg->input_pins[AUTO_PIN_FRONT_MIC]) { | ||
2798 | cfg->input_pins[AUTO_PIN_MIC] = | ||
2799 | cfg->input_pins[AUTO_PIN_FRONT_MIC]; | ||
2800 | cfg->input_pins[AUTO_PIN_FRONT_MIC] = 0; | ||
2801 | } | ||
2802 | /* ditto for line-in */ | ||
2803 | if (!cfg->input_pins[AUTO_PIN_LINE] && | ||
2804 | cfg->input_pins[AUTO_PIN_FRONT_LINE]) { | ||
2805 | cfg->input_pins[AUTO_PIN_LINE] = | ||
2806 | cfg->input_pins[AUTO_PIN_FRONT_LINE]; | ||
2807 | cfg->input_pins[AUTO_PIN_FRONT_LINE] = 0; | ||
2808 | } | ||
2809 | |||
2708 | /* | 2810 | /* |
2709 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin | 2811 | * FIX-UP: if no line-outs are detected, try to use speaker or HP pin |
2710 | * as a primary output | 2812 | * as a primary output |
@@ -2758,6 +2860,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, | |||
2758 | cfg->hp_outs, cfg->hp_pins[0], | 2860 | cfg->hp_outs, cfg->hp_pins[0], |
2759 | cfg->hp_pins[1], cfg->hp_pins[2], | 2861 | cfg->hp_pins[1], cfg->hp_pins[2], |
2760 | cfg->hp_pins[3], cfg->hp_pins[4]); | 2862 | cfg->hp_pins[3], cfg->hp_pins[4]); |
2863 | snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); | ||
2761 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," | 2864 | snd_printd(" inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x," |
2762 | " cd=0x%x, aux=0x%x\n", | 2865 | " cd=0x%x, aux=0x%x\n", |
2763 | cfg->input_pins[AUTO_PIN_MIC], | 2866 | cfg->input_pins[AUTO_PIN_MIC], |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2bce925d84ef..f14871151be9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -77,12 +77,16 @@ enum { | |||
77 | #define AC_VERB_GET_PIN_SENSE 0x0f09 | 77 | #define AC_VERB_GET_PIN_SENSE 0x0f09 |
78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a | 78 | #define AC_VERB_GET_BEEP_CONTROL 0x0f0a |
79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c | 79 | #define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c |
80 | #define AC_VERB_GET_DIGI_CONVERT 0x0f0d | 80 | #define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d |
81 | #define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e | ||
81 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f | 82 | #define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f |
82 | /* f10-f1a: GPIO */ | 83 | /* f10-f1a: GPIO */ |
83 | #define AC_VERB_GET_GPIO_DATA 0x0f15 | 84 | #define AC_VERB_GET_GPIO_DATA 0x0f15 |
84 | #define AC_VERB_GET_GPIO_MASK 0x0f16 | 85 | #define AC_VERB_GET_GPIO_MASK 0x0f16 |
85 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 | 86 | #define AC_VERB_GET_GPIO_DIRECTION 0x0f17 |
87 | #define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 | ||
88 | #define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 | ||
89 | #define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a | ||
86 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c | 90 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c |
87 | /* f20: AFG/MFG */ | 91 | /* f20: AFG/MFG */ |
88 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 | 92 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 |
@@ -110,6 +114,9 @@ enum { | |||
110 | #define AC_VERB_SET_GPIO_DATA 0x715 | 114 | #define AC_VERB_SET_GPIO_DATA 0x715 |
111 | #define AC_VERB_SET_GPIO_MASK 0x716 | 115 | #define AC_VERB_SET_GPIO_MASK 0x716 |
112 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 | 116 | #define AC_VERB_SET_GPIO_DIRECTION 0x717 |
117 | #define AC_VERB_SET_GPIO_WAKE_MASK 0x718 | ||
118 | #define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 | ||
119 | #define AC_VERB_SET_GPIO_STICKY_MASK 0x71a | ||
113 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c | 120 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c |
114 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d | 121 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d |
115 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e | 122 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e |
@@ -135,6 +142,7 @@ enum { | |||
135 | #define AC_PAR_PROC_CAP 0x10 | 142 | #define AC_PAR_PROC_CAP 0x10 |
136 | #define AC_PAR_GPIO_CAP 0x11 | 143 | #define AC_PAR_GPIO_CAP 0x11 |
137 | #define AC_PAR_AMP_OUT_CAP 0x12 | 144 | #define AC_PAR_AMP_OUT_CAP 0x12 |
145 | #define AC_PAR_VOL_KNB_CAP 0x13 | ||
138 | 146 | ||
139 | /* | 147 | /* |
140 | * AC_VERB_PARAMETERS results (32bit) | 148 | * AC_VERB_PARAMETERS results (32bit) |
@@ -181,6 +189,27 @@ enum { | |||
181 | #define AC_SUPFMT_FLOAT32 (1<<1) | 189 | #define AC_SUPFMT_FLOAT32 (1<<1) |
182 | #define AC_SUPFMT_AC3 (1<<2) | 190 | #define AC_SUPFMT_AC3 (1<<2) |
183 | 191 | ||
192 | /* GP I/O count */ | ||
193 | #define AC_GPIO_IO_COUNT (0xff<<0) | ||
194 | #define AC_GPIO_O_COUNT (0xff<<8) | ||
195 | #define AC_GPIO_O_COUNT_SHIFT 8 | ||
196 | #define AC_GPIO_I_COUNT (0xff<<16) | ||
197 | #define AC_GPIO_I_COUNT_SHIFT 16 | ||
198 | #define AC_GPIO_UNSOLICITED (1<<30) | ||
199 | #define AC_GPIO_WAKE (1<<31) | ||
200 | |||
201 | /* Converter stream, channel */ | ||
202 | #define AC_CONV_CHANNEL (0xf<<0) | ||
203 | #define AC_CONV_STREAM (0xf<<4) | ||
204 | #define AC_CONV_STREAM_SHIFT 4 | ||
205 | |||
206 | /* Input converter SDI select */ | ||
207 | #define AC_SDI_SELECT (0xf<<0) | ||
208 | |||
209 | /* Unsolicited response */ | ||
210 | #define AC_UNSOL_TAG (0x3f<<0) | ||
211 | #define AC_UNSOL_ENABLED (1<<7) | ||
212 | |||
184 | /* Pin widget capabilies */ | 213 | /* Pin widget capabilies */ |
185 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ | 214 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ |
186 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ | 215 | #define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ |
@@ -189,6 +218,10 @@ enum { | |||
189 | #define AC_PINCAP_OUT (1<<4) /* output capable */ | 218 | #define AC_PINCAP_OUT (1<<4) /* output capable */ |
190 | #define AC_PINCAP_IN (1<<5) /* input capable */ | 219 | #define AC_PINCAP_IN (1<<5) /* input capable */ |
191 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ | 220 | #define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ |
221 | /* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, | ||
222 | * but is marked reserved in the Intel HDA specification. | ||
223 | */ | ||
224 | #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ | ||
192 | #define AC_PINCAP_VREF (0x37<<8) | 225 | #define AC_PINCAP_VREF (0x37<<8) |
193 | #define AC_PINCAP_VREF_SHIFT 8 | 226 | #define AC_PINCAP_VREF_SHIFT 8 |
194 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ | 227 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ |
@@ -222,6 +255,9 @@ enum { | |||
222 | #define AC_PWRST_D3SUP (1<<3) | 255 | #define AC_PWRST_D3SUP (1<<3) |
223 | 256 | ||
224 | /* Power state values */ | 257 | /* Power state values */ |
258 | #define AC_PWRST_SETTING (0xf<<0) | ||
259 | #define AC_PWRST_ACTUAL (0xf<<4) | ||
260 | #define AC_PWRST_ACTUAL_SHIFT 4 | ||
225 | #define AC_PWRST_D0 0x00 | 261 | #define AC_PWRST_D0 0x00 |
226 | #define AC_PWRST_D1 0x01 | 262 | #define AC_PWRST_D1 0x01 |
227 | #define AC_PWRST_D2 0x02 | 263 | #define AC_PWRST_D2 0x02 |
@@ -230,10 +266,11 @@ enum { | |||
230 | /* Processing capabilies */ | 266 | /* Processing capabilies */ |
231 | #define AC_PCAP_BENIGN (1<<0) | 267 | #define AC_PCAP_BENIGN (1<<0) |
232 | #define AC_PCAP_NUM_COEF (0xff<<8) | 268 | #define AC_PCAP_NUM_COEF (0xff<<8) |
269 | #define AC_PCAP_NUM_COEF_SHIFT 8 | ||
233 | 270 | ||
234 | /* Volume knobs capabilities */ | 271 | /* Volume knobs capabilities */ |
235 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) | 272 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) |
236 | #define AC_KNBCAP_DELTA (1<<8) | 273 | #define AC_KNBCAP_DELTA (1<<7) |
237 | 274 | ||
238 | /* | 275 | /* |
239 | * Control Parameters | 276 | * Control Parameters |
@@ -266,6 +303,9 @@ enum { | |||
266 | #define AC_DIG1_PROFESSIONAL (1<<6) | 303 | #define AC_DIG1_PROFESSIONAL (1<<6) |
267 | #define AC_DIG1_LEVEL (1<<7) | 304 | #define AC_DIG1_LEVEL (1<<7) |
268 | 305 | ||
306 | /* DIGITAL2 bits */ | ||
307 | #define AC_DIG2_CC (0x7f<<0) | ||
308 | |||
269 | /* Pin widget control - 8bit */ | 309 | /* Pin widget control - 8bit */ |
270 | #define AC_PINCTL_VREFEN (0x7<<0) | 310 | #define AC_PINCTL_VREFEN (0x7<<0) |
271 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ | 311 | #define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ |
@@ -280,12 +320,22 @@ enum { | |||
280 | /* Unsolicited response - 8bit */ | 320 | /* Unsolicited response - 8bit */ |
281 | #define AC_USRSP_EN (1<<7) | 321 | #define AC_USRSP_EN (1<<7) |
282 | 322 | ||
323 | /* Pin sense - 32bit */ | ||
324 | #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) | ||
325 | #define AC_PINSENSE_PRESENCE (1<<31) | ||
326 | |||
327 | /* EAPD/BTL enable - 32bit */ | ||
328 | #define AC_EAPDBTL_BALANCED (1<<0) | ||
329 | #define AC_EAPDBTL_EAPD (1<<1) | ||
330 | #define AC_EAPDBTL_LR_SWAP (1<<2) | ||
331 | |||
283 | /* configuration default - 32bit */ | 332 | /* configuration default - 32bit */ |
284 | #define AC_DEFCFG_SEQUENCE (0xf<<0) | 333 | #define AC_DEFCFG_SEQUENCE (0xf<<0) |
285 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) | 334 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) |
286 | #define AC_DEFCFG_ASSOC_SHIFT 4 | 335 | #define AC_DEFCFG_ASSOC_SHIFT 4 |
287 | #define AC_DEFCFG_MISC (0xf<<8) | 336 | #define AC_DEFCFG_MISC (0xf<<8) |
288 | #define AC_DEFCFG_MISC_SHIFT 8 | 337 | #define AC_DEFCFG_MISC_SHIFT 8 |
338 | #define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) | ||
289 | #define AC_DEFCFG_COLOR (0xf<<12) | 339 | #define AC_DEFCFG_COLOR (0xf<<12) |
290 | #define AC_DEFCFG_COLOR_SHIFT 12 | 340 | #define AC_DEFCFG_COLOR_SHIFT 12 |
291 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) | 341 | #define AC_DEFCFG_CONN_TYPE (0xf<<16) |
@@ -417,7 +467,7 @@ struct hda_bus_ops { | |||
417 | /* free the private data */ | 467 | /* free the private data */ |
418 | void (*private_free)(struct hda_bus *); | 468 | void (*private_free)(struct hda_bus *); |
419 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 469 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
420 | /* notify power-up/down from codec to contoller */ | 470 | /* notify power-up/down from codec to controller */ |
421 | void (*pm_notify)(struct hda_codec *codec); | 471 | void (*pm_notify)(struct hda_codec *codec); |
422 | #endif | 472 | #endif |
423 | }; | 473 | }; |
@@ -456,6 +506,9 @@ struct hda_bus { | |||
456 | struct hda_bus_unsolicited *unsol; | 506 | struct hda_bus_unsolicited *unsol; |
457 | 507 | ||
458 | struct snd_info_entry *proc; | 508 | struct snd_info_entry *proc; |
509 | |||
510 | /* misc op flags */ | ||
511 | unsigned int needs_damn_long_delay :1; | ||
459 | }; | 512 | }; |
460 | 513 | ||
461 | /* | 514 | /* |
@@ -470,6 +523,7 @@ struct hda_codec_preset { | |||
470 | unsigned int subs; | 523 | unsigned int subs; |
471 | unsigned int subs_mask; | 524 | unsigned int subs_mask; |
472 | unsigned int rev; | 525 | unsigned int rev; |
526 | hda_nid_t afg, mfg; | ||
473 | const char *name; | 527 | const char *name; |
474 | int (*patch)(struct hda_codec *codec); | 528 | int (*patch)(struct hda_codec *codec); |
475 | }; | 529 | }; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c957eb58de5c..f9de7c467c25 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index bafb7b01f5a1..2177d9af5334 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3fa0f9704909..56f8a3050751 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -34,7 +34,6 @@ | |||
34 | * | 34 | * |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <sound/driver.h> | ||
38 | #include <asm/io.h> | 37 | #include <asm/io.h> |
39 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
40 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
@@ -50,29 +49,32 @@ | |||
50 | #include "hda_codec.h" | 49 | #include "hda_codec.h" |
51 | 50 | ||
52 | 51 | ||
53 | static int index = SNDRV_DEFAULT_IDX1; | 52 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
54 | static char *id = SNDRV_DEFAULT_STR1; | 53 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
55 | static char *model; | 54 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
56 | static int position_fix; | 55 | static char *model[SNDRV_CARDS]; |
57 | static int probe_mask = -1; | 56 | static int position_fix[SNDRV_CARDS]; |
57 | static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; | ||
58 | static int single_cmd; | 58 | static int single_cmd; |
59 | static int enable_msi; | 59 | static int enable_msi; |
60 | 60 | ||
61 | module_param(index, int, 0444); | 61 | module_param_array(index, int, NULL, 0444); |
62 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); | 62 | MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); |
63 | module_param(id, charp, 0444); | 63 | module_param_array(id, charp, NULL, 0444); |
64 | MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); | 64 | MODULE_PARM_DESC(id, "ID string for Intel HD audio interface."); |
65 | module_param(model, charp, 0444); | 65 | module_param_array(enable, bool, NULL, 0444); |
66 | MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); | ||
67 | module_param_array(model, charp, NULL, 0444); | ||
66 | MODULE_PARM_DESC(model, "Use the given board model."); | 68 | MODULE_PARM_DESC(model, "Use the given board model."); |
67 | module_param(position_fix, int, 0444); | 69 | module_param_array(position_fix, int, NULL, 0444); |
68 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " | 70 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer " |
69 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); | 71 | "(0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); |
70 | module_param(probe_mask, int, 0444); | 72 | module_param_array(probe_mask, int, NULL, 0444); |
71 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); | 73 | MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); |
72 | module_param(single_cmd, bool, 0444); | 74 | module_param(single_cmd, bool, 0444); |
73 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " | 75 | MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " |
74 | "(for debugging only)."); | 76 | "(for debugging only)."); |
75 | module_param(enable_msi, int, 0); | 77 | module_param(enable_msi, int, 0444); |
76 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); | 78 | MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); |
77 | 79 | ||
78 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 80 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
@@ -87,10 +89,6 @@ module_param(power_save_controller, bool, 0644); | |||
87 | MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); | 89 | MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); |
88 | #endif | 90 | #endif |
89 | 91 | ||
90 | /* just for backward compatibility */ | ||
91 | static int enable; | ||
92 | module_param(enable, bool, 0444); | ||
93 | |||
94 | MODULE_LICENSE("GPL"); | 92 | MODULE_LICENSE("GPL"); |
95 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | 93 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," |
96 | "{Intel, ICH6M}," | 94 | "{Intel, ICH6M}," |
@@ -98,12 +96,20 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
98 | "{Intel, ESB2}," | 96 | "{Intel, ESB2}," |
99 | "{Intel, ICH8}," | 97 | "{Intel, ICH8}," |
100 | "{Intel, ICH9}," | 98 | "{Intel, ICH9}," |
99 | "{Intel, ICH10}," | ||
100 | "{Intel, SCH}," | ||
101 | "{ATI, SB450}," | 101 | "{ATI, SB450}," |
102 | "{ATI, SB600}," | 102 | "{ATI, SB600}," |
103 | "{ATI, RS600}," | 103 | "{ATI, RS600}," |
104 | "{ATI, RS690}," | 104 | "{ATI, RS690}," |
105 | "{ATI, RS780}," | 105 | "{ATI, RS780}," |
106 | "{ATI, R600}," | 106 | "{ATI, R600}," |
107 | "{ATI, RV630}," | ||
108 | "{ATI, RV610}," | ||
109 | "{ATI, RV670}," | ||
110 | "{ATI, RV635}," | ||
111 | "{ATI, RV620}," | ||
112 | "{ATI, RV770}," | ||
107 | "{VIA, VT8251}," | 113 | "{VIA, VT8251}," |
108 | "{VIA, VT8237A}," | 114 | "{VIA, VT8237A}," |
109 | "{SiS, SIS966}," | 115 | "{SiS, SIS966}," |
@@ -370,6 +376,7 @@ struct azx { | |||
370 | /* driver types */ | 376 | /* driver types */ |
371 | enum { | 377 | enum { |
372 | AZX_DRIVER_ICH, | 378 | AZX_DRIVER_ICH, |
379 | AZX_DRIVER_SCH, | ||
373 | AZX_DRIVER_ATI, | 380 | AZX_DRIVER_ATI, |
374 | AZX_DRIVER_ATIHDMI, | 381 | AZX_DRIVER_ATIHDMI, |
375 | AZX_DRIVER_VIA, | 382 | AZX_DRIVER_VIA, |
@@ -380,6 +387,7 @@ enum { | |||
380 | 387 | ||
381 | static char *driver_short_names[] __devinitdata = { | 388 | static char *driver_short_names[] __devinitdata = { |
382 | [AZX_DRIVER_ICH] = "HDA Intel", | 389 | [AZX_DRIVER_ICH] = "HDA Intel", |
390 | [AZX_DRIVER_SCH] = "HDA Intel MID", | ||
383 | [AZX_DRIVER_ATI] = "HDA ATI SB", | 391 | [AZX_DRIVER_ATI] = "HDA ATI SB", |
384 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", | 392 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", |
385 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", | 393 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", |
@@ -547,7 +555,7 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) | |||
547 | 555 | ||
548 | again: | 556 | again: |
549 | timeout = jiffies + msecs_to_jiffies(1000); | 557 | timeout = jiffies + msecs_to_jiffies(1000); |
550 | do { | 558 | for (;;) { |
551 | if (chip->polling_mode) { | 559 | if (chip->polling_mode) { |
552 | spin_lock_irq(&chip->reg_lock); | 560 | spin_lock_irq(&chip->reg_lock); |
553 | azx_update_rirb(chip); | 561 | azx_update_rirb(chip); |
@@ -555,8 +563,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec) | |||
555 | } | 563 | } |
556 | if (!chip->rirb.cmds) | 564 | if (!chip->rirb.cmds) |
557 | return chip->rirb.res; /* the last value */ | 565 | return chip->rirb.res; /* the last value */ |
558 | schedule_timeout_uninterruptible(1); | 566 | if (time_after(jiffies, timeout)) |
559 | } while (time_after_eq(timeout, jiffies)); | 567 | break; |
568 | if (codec->bus->needs_damn_long_delay) | ||
569 | msleep(2); /* temporary workaround */ | ||
570 | else { | ||
571 | udelay(10); | ||
572 | cond_resched(); | ||
573 | } | ||
574 | } | ||
560 | 575 | ||
561 | if (chip->msi) { | 576 | if (chip->msi) { |
562 | snd_printk(KERN_WARNING "hda_intel: No response from codec, " | 577 | snd_printk(KERN_WARNING "hda_intel: No response from codec, " |
@@ -618,8 +633,9 @@ static int azx_single_send_cmd(struct hda_codec *codec, u32 val) | |||
618 | } | 633 | } |
619 | udelay(1); | 634 | udelay(1); |
620 | } | 635 | } |
621 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", | 636 | if (printk_ratelimit()) |
622 | azx_readw(chip, IRS), val); | 637 | snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", |
638 | azx_readw(chip, IRS), val); | ||
623 | return -EIO; | 639 | return -EIO; |
624 | } | 640 | } |
625 | 641 | ||
@@ -635,8 +651,9 @@ static unsigned int azx_single_get_response(struct hda_codec *codec) | |||
635 | return azx_readl(chip, IR); | 651 | return azx_readl(chip, IR); |
636 | udelay(1); | 652 | udelay(1); |
637 | } | 653 | } |
638 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | 654 | if (printk_ratelimit()) |
639 | azx_readw(chip, IRS)); | 655 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", |
656 | azx_readw(chip, IRS)); | ||
640 | return (unsigned int)-1; | 657 | return (unsigned int)-1; |
641 | } | 658 | } |
642 | 659 | ||
@@ -1031,7 +1048,8 @@ static unsigned int azx_max_codecs[] __devinitdata = { | |||
1031 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ | 1048 | [AZX_DRIVER_NVIDIA] = 3, /* FIXME: correct? */ |
1032 | }; | 1049 | }; |
1033 | 1050 | ||
1034 | static int __devinit azx_codec_create(struct azx *chip, const char *model) | 1051 | static int __devinit azx_codec_create(struct azx *chip, const char *model, |
1052 | unsigned int codec_probe_mask) | ||
1035 | { | 1053 | { |
1036 | struct hda_bus_template bus_temp; | 1054 | struct hda_bus_template bus_temp; |
1037 | int c, codecs, audio_codecs, err; | 1055 | int c, codecs, audio_codecs, err; |
@@ -1052,7 +1070,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1052 | 1070 | ||
1053 | codecs = audio_codecs = 0; | 1071 | codecs = audio_codecs = 0; |
1054 | for (c = 0; c < AZX_MAX_CODECS; c++) { | 1072 | for (c = 0; c < AZX_MAX_CODECS; c++) { |
1055 | if ((chip->codec_mask & (1 << c)) & probe_mask) { | 1073 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { |
1056 | struct hda_codec *codec; | 1074 | struct hda_codec *codec; |
1057 | err = snd_hda_codec_new(chip->bus, c, &codec); | 1075 | err = snd_hda_codec_new(chip->bus, c, &codec); |
1058 | if (err < 0) | 1076 | if (err < 0) |
@@ -1065,7 +1083,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) | |||
1065 | if (!audio_codecs) { | 1083 | if (!audio_codecs) { |
1066 | /* probe additional slots if no codec is found */ | 1084 | /* probe additional slots if no codec is found */ |
1067 | for (; c < azx_max_codecs[chip->driver_type]; c++) { | 1085 | for (; c < azx_max_codecs[chip->driver_type]; c++) { |
1068 | if ((chip->codec_mask & (1 << c)) & probe_mask) { | 1086 | if ((chip->codec_mask & (1 << c)) & codec_probe_mask) { |
1069 | err = snd_hda_codec_new(chip->bus, c, NULL); | 1087 | err = snd_hda_codec_new(chip->bus, c, NULL); |
1070 | if (err < 0) | 1088 | if (err < 0) |
1071 | continue; | 1089 | continue; |
@@ -1676,18 +1694,18 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | |||
1676 | {} | 1694 | {} |
1677 | }; | 1695 | }; |
1678 | 1696 | ||
1679 | static void __devinit check_probe_mask(struct azx *chip) | 1697 | static void __devinit check_probe_mask(struct azx *chip, int dev) |
1680 | { | 1698 | { |
1681 | const struct snd_pci_quirk *q; | 1699 | const struct snd_pci_quirk *q; |
1682 | 1700 | ||
1683 | if (probe_mask == -1) { | 1701 | if (probe_mask[dev] == -1) { |
1684 | q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); | 1702 | q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); |
1685 | if (q) { | 1703 | if (q) { |
1686 | printk(KERN_INFO | 1704 | printk(KERN_INFO |
1687 | "hda_intel: probe_mask set to 0x%x " | 1705 | "hda_intel: probe_mask set to 0x%x " |
1688 | "for device %04x:%04x\n", | 1706 | "for device %04x:%04x\n", |
1689 | q->value, q->subvendor, q->subdevice); | 1707 | q->value, q->subvendor, q->subdevice); |
1690 | probe_mask = q->value; | 1708 | probe_mask[dev] = q->value; |
1691 | } | 1709 | } |
1692 | } | 1710 | } |
1693 | } | 1711 | } |
@@ -1697,17 +1715,18 @@ static void __devinit check_probe_mask(struct azx *chip) | |||
1697 | * constructor | 1715 | * constructor |
1698 | */ | 1716 | */ |
1699 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | 1717 | static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, |
1700 | int driver_type, | 1718 | int dev, int driver_type, |
1701 | struct azx **rchip) | 1719 | struct azx **rchip) |
1702 | { | 1720 | { |
1703 | struct azx *chip; | 1721 | struct azx *chip; |
1704 | int err; | 1722 | int err; |
1723 | unsigned short gcap; | ||
1705 | static struct snd_device_ops ops = { | 1724 | static struct snd_device_ops ops = { |
1706 | .dev_free = azx_dev_free, | 1725 | .dev_free = azx_dev_free, |
1707 | }; | 1726 | }; |
1708 | 1727 | ||
1709 | *rchip = NULL; | 1728 | *rchip = NULL; |
1710 | 1729 | ||
1711 | err = pci_enable_device(pci); | 1730 | err = pci_enable_device(pci); |
1712 | if (err < 0) | 1731 | if (err < 0) |
1713 | return err; | 1732 | return err; |
@@ -1727,8 +1746,8 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1727 | chip->driver_type = driver_type; | 1746 | chip->driver_type = driver_type; |
1728 | chip->msi = enable_msi; | 1747 | chip->msi = enable_msi; |
1729 | 1748 | ||
1730 | chip->position_fix = check_position_fix(chip, position_fix); | 1749 | chip->position_fix = check_position_fix(chip, position_fix[dev]); |
1731 | check_probe_mask(chip); | 1750 | check_probe_mask(chip, dev); |
1732 | 1751 | ||
1733 | chip->single_cmd = single_cmd; | 1752 | chip->single_cmd = single_cmd; |
1734 | 1753 | ||
@@ -1769,25 +1788,40 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
1769 | pci_set_master(pci); | 1788 | pci_set_master(pci); |
1770 | synchronize_irq(chip->irq); | 1789 | synchronize_irq(chip->irq); |
1771 | 1790 | ||
1772 | switch (chip->driver_type) { | 1791 | gcap = azx_readw(chip, GCAP); |
1773 | case AZX_DRIVER_ULI: | 1792 | snd_printdd("chipset global capabilities = 0x%x\n", gcap); |
1774 | chip->playback_streams = ULI_NUM_PLAYBACK; | 1793 | |
1775 | chip->capture_streams = ULI_NUM_CAPTURE; | 1794 | if (gcap) { |
1776 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; | 1795 | /* read number of streams from GCAP register instead of using |
1777 | chip->capture_index_offset = ULI_CAPTURE_INDEX; | 1796 | * hardcoded value |
1778 | break; | 1797 | */ |
1779 | case AZX_DRIVER_ATIHDMI: | 1798 | chip->playback_streams = (gcap & (0xF << 12)) >> 12; |
1780 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | 1799 | chip->capture_streams = (gcap & (0xF << 8)) >> 8; |
1781 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | 1800 | chip->playback_index_offset = (gcap & (0xF << 12)) >> 12; |
1782 | chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | 1801 | chip->capture_index_offset = 0; |
1783 | chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | 1802 | } else { |
1784 | break; | 1803 | /* gcap didn't give any info, switching to old method */ |
1785 | default: | 1804 | |
1786 | chip->playback_streams = ICH6_NUM_PLAYBACK; | 1805 | switch (chip->driver_type) { |
1787 | chip->capture_streams = ICH6_NUM_CAPTURE; | 1806 | case AZX_DRIVER_ULI: |
1788 | chip->playback_index_offset = ICH6_PLAYBACK_INDEX; | 1807 | chip->playback_streams = ULI_NUM_PLAYBACK; |
1789 | chip->capture_index_offset = ICH6_CAPTURE_INDEX; | 1808 | chip->capture_streams = ULI_NUM_CAPTURE; |
1790 | break; | 1809 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; |
1810 | chip->capture_index_offset = ULI_CAPTURE_INDEX; | ||
1811 | break; | ||
1812 | case AZX_DRIVER_ATIHDMI: | ||
1813 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | ||
1814 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | ||
1815 | chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | ||
1816 | chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | ||
1817 | break; | ||
1818 | default: | ||
1819 | chip->playback_streams = ICH6_NUM_PLAYBACK; | ||
1820 | chip->capture_streams = ICH6_NUM_CAPTURE; | ||
1821 | chip->playback_index_offset = ICH6_PLAYBACK_INDEX; | ||
1822 | chip->capture_index_offset = ICH6_CAPTURE_INDEX; | ||
1823 | break; | ||
1824 | } | ||
1791 | } | 1825 | } |
1792 | chip->num_streams = chip->playback_streams + chip->capture_streams; | 1826 | chip->num_streams = chip->playback_streams + chip->capture_streams; |
1793 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), | 1827 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), |
@@ -1869,17 +1903,25 @@ static void power_down_all_codecs(struct azx *chip) | |||
1869 | static int __devinit azx_probe(struct pci_dev *pci, | 1903 | static int __devinit azx_probe(struct pci_dev *pci, |
1870 | const struct pci_device_id *pci_id) | 1904 | const struct pci_device_id *pci_id) |
1871 | { | 1905 | { |
1906 | static int dev; | ||
1872 | struct snd_card *card; | 1907 | struct snd_card *card; |
1873 | struct azx *chip; | 1908 | struct azx *chip; |
1874 | int err; | 1909 | int err; |
1875 | 1910 | ||
1876 | card = snd_card_new(index, id, THIS_MODULE, 0); | 1911 | if (dev >= SNDRV_CARDS) |
1912 | return -ENODEV; | ||
1913 | if (!enable[dev]) { | ||
1914 | dev++; | ||
1915 | return -ENOENT; | ||
1916 | } | ||
1917 | |||
1918 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1877 | if (!card) { | 1919 | if (!card) { |
1878 | snd_printk(KERN_ERR SFX "Error creating card!\n"); | 1920 | snd_printk(KERN_ERR SFX "Error creating card!\n"); |
1879 | return -ENOMEM; | 1921 | return -ENOMEM; |
1880 | } | 1922 | } |
1881 | 1923 | ||
1882 | err = azx_create(card, pci, pci_id->driver_data, &chip); | 1924 | err = azx_create(card, pci, dev, pci_id->driver_data, &chip); |
1883 | if (err < 0) { | 1925 | if (err < 0) { |
1884 | snd_card_free(card); | 1926 | snd_card_free(card); |
1885 | return err; | 1927 | return err; |
@@ -1887,7 +1929,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
1887 | card->private_data = chip; | 1929 | card->private_data = chip; |
1888 | 1930 | ||
1889 | /* create codec instances */ | 1931 | /* create codec instances */ |
1890 | err = azx_codec_create(chip, model); | 1932 | err = azx_codec_create(chip, model[dev], probe_mask[dev]); |
1891 | if (err < 0) { | 1933 | if (err < 0) { |
1892 | snd_card_free(card); | 1934 | snd_card_free(card); |
1893 | return err; | 1935 | return err; |
@@ -1919,6 +1961,7 @@ static int __devinit azx_probe(struct pci_dev *pci, | |||
1919 | chip->running = 1; | 1961 | chip->running = 1; |
1920 | power_down_all_codecs(chip); | 1962 | power_down_all_codecs(chip); |
1921 | 1963 | ||
1964 | dev++; | ||
1922 | return err; | 1965 | return err; |
1923 | } | 1966 | } |
1924 | 1967 | ||
@@ -1936,12 +1979,21 @@ static struct pci_device_id azx_ids[] = { | |||
1936 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ | 1979 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ |
1937 | { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ | 1980 | { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ |
1938 | { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ | 1981 | { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */ |
1982 | { 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */ | ||
1983 | { 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */ | ||
1984 | { 0x8086, 0x811b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SCH }, /* SCH*/ | ||
1939 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ | 1985 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ |
1940 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ | 1986 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ |
1941 | { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ | 1987 | { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ |
1942 | { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */ | 1988 | { 0x1002, 0x7919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS690 HDMI */ |
1943 | { 0x1002, 0x960c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */ | 1989 | { 0x1002, 0x960f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS780 HDMI */ |
1944 | { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */ | 1990 | { 0x1002, 0xaa00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI R600 HDMI */ |
1991 | { 0x1002, 0xaa08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV630 HDMI */ | ||
1992 | { 0x1002, 0xaa10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV610 HDMI */ | ||
1993 | { 0x1002, 0xaa18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV670 HDMI */ | ||
1994 | { 0x1002, 0xaa20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV635 HDMI */ | ||
1995 | { 0x1002, 0xaa28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV620 HDMI */ | ||
1996 | { 0x1002, 0xaa30, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RV770 HDMI */ | ||
1945 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ | 1997 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ |
1946 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ | 1998 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ |
1947 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ | 1999 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 20c5e6250374..ad0014ab71f9 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -90,6 +90,13 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | 90 | void snd_hda_codec_resume_amp(struct hda_codec *codec); |
91 | #endif | 91 | #endif |
92 | 92 | ||
93 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | ||
94 | unsigned int *tlv); | ||
95 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | ||
96 | const char *name); | ||
97 | int snd_hda_add_vmaster(struct hda_codec *codec, char *name, | ||
98 | unsigned int *tlv, const char **slaves); | ||
99 | |||
93 | /* amp value bits */ | 100 | /* amp value bits */ |
94 | #define HDA_AMP_MUTE 0x80 | 101 | #define HDA_AMP_MUTE 0x80 |
95 | #define HDA_AMP_UNMUTE 0x00 | 102 | #define HDA_AMP_UNMUTE 0x00 |
@@ -220,6 +227,7 @@ struct hda_multi_out { | |||
220 | hda_nid_t dig_out_nid; /* digital out audio widget */ | 227 | hda_nid_t dig_out_nid; /* digital out audio widget */ |
221 | int max_channels; /* currently supported analog channels */ | 228 | int max_channels; /* currently supported analog channels */ |
222 | int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ | 229 | int dig_out_used; /* current usage of digital out (HDA_DIG_XXX) */ |
230 | int no_share_stream; /* don't share a stream with multiple pins */ | ||
223 | }; | 231 | }; |
224 | 232 | ||
225 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, | 233 | int snd_hda_multi_out_dig_open(struct hda_codec *codec, |
@@ -324,6 +332,7 @@ struct auto_pin_cfg { | |||
324 | hda_nid_t input_pins[AUTO_PIN_LAST]; | 332 | hda_nid_t input_pins[AUTO_PIN_LAST]; |
325 | hda_nid_t dig_out_pin; | 333 | hda_nid_t dig_out_pin; |
326 | hda_nid_t dig_in_pin; | 334 | hda_nid_t dig_in_pin; |
335 | hda_nid_t mono_out_pin; | ||
327 | }; | 336 | }; |
328 | 337 | ||
329 | #define get_defcfg_connect(cfg) \ | 338 | #define get_defcfg_connect(cfg) \ |
@@ -362,10 +371,11 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) | |||
362 | { | 371 | { |
363 | if (nid < codec->start_nid || | 372 | if (nid < codec->start_nid || |
364 | nid >= codec->start_nid + codec->num_nodes) | 373 | nid >= codec->start_nid + codec->num_nodes) |
365 | return snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); | 374 | return 0; |
366 | return codec->wcaps[nid - codec->start_nid]; | 375 | return codec->wcaps[nid - codec->start_nid]; |
367 | } | 376 | } |
368 | 377 | ||
378 | u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); | ||
369 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | 379 | int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, |
370 | unsigned int caps); | 380 | unsigned int caps); |
371 | 381 | ||
@@ -397,4 +407,11 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, | |||
397 | hda_nid_t nid); | 407 | hda_nid_t nid); |
398 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ | 408 | #endif /* CONFIG_SND_HDA_POWER_SAVE */ |
399 | 409 | ||
410 | /* | ||
411 | * virtual master control | ||
412 | */ | ||
413 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | ||
414 | const unsigned int *tlv); | ||
415 | int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave); | ||
416 | |||
400 | #endif /* __SOUND_HDA_LOCAL_H */ | 417 | #endif /* __SOUND_HDA_LOCAL_H */ |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e94944f34ffd..35a630d1770f 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
27 | #include "hda_codec.h" | 26 | #include "hda_codec.h" |
@@ -203,7 +202,8 @@ static const char *get_jack_color(u32 cfg) | |||
203 | } | 202 | } |
204 | 203 | ||
205 | static void print_pin_caps(struct snd_info_buffer *buffer, | 204 | static void print_pin_caps(struct snd_info_buffer *buffer, |
206 | struct hda_codec *codec, hda_nid_t nid) | 205 | struct hda_codec *codec, hda_nid_t nid, |
206 | int *supports_vref) | ||
207 | { | 207 | { |
208 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; | 208 | static char *jack_conns[4] = { "Jack", "N/A", "Fixed", "Both" }; |
209 | static char *jack_types[16] = { | 209 | static char *jack_types[16] = { |
@@ -213,7 +213,7 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
213 | "SPDIF In", "Digitial In", "Reserved", "Other" | 213 | "SPDIF In", "Digitial In", "Reserved", "Other" |
214 | }; | 214 | }; |
215 | static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; | 215 | static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; |
216 | unsigned int caps; | 216 | unsigned int caps, val; |
217 | 217 | ||
218 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | 218 | caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); |
219 | snd_iprintf(buffer, " Pincap 0x08%x:", caps); | 219 | snd_iprintf(buffer, " Pincap 0x08%x:", caps); |
@@ -227,7 +227,45 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
227 | snd_iprintf(buffer, " EAPD"); | 227 | snd_iprintf(buffer, " EAPD"); |
228 | if (caps & AC_PINCAP_PRES_DETECT) | 228 | if (caps & AC_PINCAP_PRES_DETECT) |
229 | snd_iprintf(buffer, " Detect"); | 229 | snd_iprintf(buffer, " Detect"); |
230 | if (caps & AC_PINCAP_BALANCE) | ||
231 | snd_iprintf(buffer, " Balanced"); | ||
232 | if (caps & AC_PINCAP_LR_SWAP) | ||
233 | snd_iprintf(buffer, " R/L"); | ||
234 | if (caps & AC_PINCAP_TRIG_REQ) | ||
235 | snd_iprintf(buffer, " Trigger"); | ||
236 | if (caps & AC_PINCAP_IMP_SENSE) | ||
237 | snd_iprintf(buffer, " ImpSense"); | ||
230 | snd_iprintf(buffer, "\n"); | 238 | snd_iprintf(buffer, "\n"); |
239 | if (caps & AC_PINCAP_VREF) { | ||
240 | unsigned int vref = | ||
241 | (caps & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | ||
242 | snd_iprintf(buffer, " Vref caps:"); | ||
243 | if (vref & AC_PINCAP_VREF_HIZ) | ||
244 | snd_iprintf(buffer, " HIZ"); | ||
245 | if (vref & AC_PINCAP_VREF_50) | ||
246 | snd_iprintf(buffer, " 50"); | ||
247 | if (vref & AC_PINCAP_VREF_GRD) | ||
248 | snd_iprintf(buffer, " GRD"); | ||
249 | if (vref & AC_PINCAP_VREF_80) | ||
250 | snd_iprintf(buffer, " 80"); | ||
251 | if (vref & AC_PINCAP_VREF_100) | ||
252 | snd_iprintf(buffer, " 100"); | ||
253 | snd_iprintf(buffer, "\n"); | ||
254 | *supports_vref = 1; | ||
255 | } else | ||
256 | *supports_vref = 0; | ||
257 | if (caps & AC_PINCAP_EAPD) { | ||
258 | val = snd_hda_codec_read(codec, nid, 0, | ||
259 | AC_VERB_GET_EAPD_BTLENABLE, 0); | ||
260 | snd_iprintf(buffer, " EAPD 0x%x:", val); | ||
261 | if (val & AC_EAPDBTL_BALANCED) | ||
262 | snd_iprintf(buffer, " BALANCED"); | ||
263 | if (val & AC_EAPDBTL_EAPD) | ||
264 | snd_iprintf(buffer, " EAPD"); | ||
265 | if (val & AC_EAPDBTL_LR_SWAP) | ||
266 | snd_iprintf(buffer, " R/L"); | ||
267 | snd_iprintf(buffer, "\n"); | ||
268 | } | ||
231 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 269 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
232 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, | 270 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, |
233 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], | 271 | jack_conns[(caps & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT], |
@@ -237,8 +275,233 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
237 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", | 275 | snd_iprintf(buffer, " Conn = %s, Color = %s\n", |
238 | get_jack_connection(caps), | 276 | get_jack_connection(caps), |
239 | get_jack_color(caps)); | 277 | get_jack_color(caps)); |
278 | /* Default association and sequence values refer to default grouping | ||
279 | * of pin complexes and their sequence within the group. This is used | ||
280 | * for priority and resource allocation. | ||
281 | */ | ||
282 | snd_iprintf(buffer, " DefAssociation = 0x%x, Sequence = 0x%x\n", | ||
283 | (caps & AC_DEFCFG_DEF_ASSOC) >> AC_DEFCFG_ASSOC_SHIFT, | ||
284 | caps & AC_DEFCFG_SEQUENCE); | ||
285 | if (((caps & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) & | ||
286 | AC_DEFCFG_MISC_NO_PRESENCE) { | ||
287 | /* Miscellaneous bit indicates external hardware does not | ||
288 | * support presence detection even if the pin complex | ||
289 | * indicates it is supported. | ||
290 | */ | ||
291 | snd_iprintf(buffer, " Misc = NO_PRESENCE\n"); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | static void print_pin_ctls(struct snd_info_buffer *buffer, | ||
296 | struct hda_codec *codec, hda_nid_t nid, | ||
297 | int supports_vref) | ||
298 | { | ||
299 | unsigned int pinctls; | ||
300 | |||
301 | pinctls = snd_hda_codec_read(codec, nid, 0, | ||
302 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
303 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | ||
304 | if (pinctls & AC_PINCTL_IN_EN) | ||
305 | snd_iprintf(buffer, " IN"); | ||
306 | if (pinctls & AC_PINCTL_OUT_EN) | ||
307 | snd_iprintf(buffer, " OUT"); | ||
308 | if (pinctls & AC_PINCTL_HP_EN) | ||
309 | snd_iprintf(buffer, " HP"); | ||
310 | if (supports_vref) { | ||
311 | int vref = pinctls & AC_PINCTL_VREFEN; | ||
312 | switch (vref) { | ||
313 | case AC_PINCTL_VREF_HIZ: | ||
314 | snd_iprintf(buffer, " VREF_HIZ"); | ||
315 | break; | ||
316 | case AC_PINCTL_VREF_50: | ||
317 | snd_iprintf(buffer, " VREF_50"); | ||
318 | break; | ||
319 | case AC_PINCTL_VREF_GRD: | ||
320 | snd_iprintf(buffer, " VREF_GRD"); | ||
321 | break; | ||
322 | case AC_PINCTL_VREF_80: | ||
323 | snd_iprintf(buffer, " VREF_80"); | ||
324 | break; | ||
325 | case AC_PINCTL_VREF_100: | ||
326 | snd_iprintf(buffer, " VREF_100"); | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | snd_iprintf(buffer, "\n"); | ||
331 | } | ||
332 | |||
333 | static void print_vol_knob(struct snd_info_buffer *buffer, | ||
334 | struct hda_codec *codec, hda_nid_t nid) | ||
335 | { | ||
336 | unsigned int cap = snd_hda_param_read(codec, nid, | ||
337 | AC_PAR_VOL_KNB_CAP); | ||
338 | snd_iprintf(buffer, " Volume-Knob: delta=%d, steps=%d, ", | ||
339 | (cap >> 7) & 1, cap & 0x7f); | ||
340 | cap = snd_hda_codec_read(codec, nid, 0, | ||
341 | AC_VERB_GET_VOLUME_KNOB_CONTROL, 0); | ||
342 | snd_iprintf(buffer, "direct=%d, val=%d\n", | ||
343 | (cap >> 7) & 1, cap & 0x7f); | ||
344 | } | ||
345 | |||
346 | static void print_audio_io(struct snd_info_buffer *buffer, | ||
347 | struct hda_codec *codec, hda_nid_t nid, | ||
348 | unsigned int wid_type) | ||
349 | { | ||
350 | int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
351 | snd_iprintf(buffer, | ||
352 | " Converter: stream=%d, channel=%d\n", | ||
353 | (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, | ||
354 | conv & AC_CONV_CHANNEL); | ||
355 | |||
356 | if (wid_type == AC_WID_AUD_IN && (conv & AC_CONV_CHANNEL) == 0) { | ||
357 | int sdi = snd_hda_codec_read(codec, nid, 0, | ||
358 | AC_VERB_GET_SDI_SELECT, 0); | ||
359 | snd_iprintf(buffer, " SDI-Select: %d\n", | ||
360 | sdi & AC_SDI_SELECT); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | static void print_digital_conv(struct snd_info_buffer *buffer, | ||
365 | struct hda_codec *codec, hda_nid_t nid) | ||
366 | { | ||
367 | unsigned int digi1 = snd_hda_codec_read(codec, nid, 0, | ||
368 | AC_VERB_GET_DIGI_CONVERT_1, 0); | ||
369 | unsigned int digi2 = snd_hda_codec_read(codec, nid, 0, | ||
370 | AC_VERB_GET_DIGI_CONVERT_2, 0); | ||
371 | snd_iprintf(buffer, " Digital:"); | ||
372 | if (digi1 & AC_DIG1_ENABLE) | ||
373 | snd_iprintf(buffer, " Enabled"); | ||
374 | if (digi1 & AC_DIG1_V) | ||
375 | snd_iprintf(buffer, " Validity"); | ||
376 | if (digi1 & AC_DIG1_VCFG) | ||
377 | snd_iprintf(buffer, " ValidityCfg"); | ||
378 | if (digi1 & AC_DIG1_EMPHASIS) | ||
379 | snd_iprintf(buffer, " Preemphasis"); | ||
380 | if (digi1 & AC_DIG1_COPYRIGHT) | ||
381 | snd_iprintf(buffer, " Copyright"); | ||
382 | if (digi1 & AC_DIG1_NONAUDIO) | ||
383 | snd_iprintf(buffer, " Non-Audio"); | ||
384 | if (digi1 & AC_DIG1_PROFESSIONAL) | ||
385 | snd_iprintf(buffer, " Pro"); | ||
386 | if (digi1 & AC_DIG1_LEVEL) | ||
387 | snd_iprintf(buffer, " GenLevel"); | ||
388 | snd_iprintf(buffer, "\n"); | ||
389 | snd_iprintf(buffer, " Digital category: 0x%x\n", digi2 & AC_DIG2_CC); | ||
390 | } | ||
391 | |||
392 | static const char *get_pwr_state(u32 state) | ||
393 | { | ||
394 | static const char *buf[4] = { | ||
395 | "D0", "D1", "D2", "D3" | ||
396 | }; | ||
397 | if (state < 4) | ||
398 | return buf[state]; | ||
399 | return "UNKNOWN"; | ||
400 | } | ||
401 | |||
402 | static void print_power_state(struct snd_info_buffer *buffer, | ||
403 | struct hda_codec *codec, hda_nid_t nid) | ||
404 | { | ||
405 | int pwr = snd_hda_codec_read(codec, nid, 0, | ||
406 | AC_VERB_GET_POWER_STATE, 0); | ||
407 | snd_iprintf(buffer, " Power: setting=%s, actual=%s\n", | ||
408 | get_pwr_state(pwr & AC_PWRST_SETTING), | ||
409 | get_pwr_state((pwr & AC_PWRST_ACTUAL) >> | ||
410 | AC_PWRST_ACTUAL_SHIFT)); | ||
411 | } | ||
412 | |||
413 | static void print_unsol_cap(struct snd_info_buffer *buffer, | ||
414 | struct hda_codec *codec, hda_nid_t nid) | ||
415 | { | ||
416 | int unsol = snd_hda_codec_read(codec, nid, 0, | ||
417 | AC_VERB_GET_UNSOLICITED_RESPONSE, 0); | ||
418 | snd_iprintf(buffer, | ||
419 | " Unsolicited: tag=%02x, enabled=%d\n", | ||
420 | unsol & AC_UNSOL_TAG, | ||
421 | (unsol & AC_UNSOL_ENABLED) ? 1 : 0); | ||
422 | } | ||
423 | |||
424 | static void print_proc_caps(struct snd_info_buffer *buffer, | ||
425 | struct hda_codec *codec, hda_nid_t nid) | ||
426 | { | ||
427 | unsigned int proc_caps = snd_hda_param_read(codec, nid, | ||
428 | AC_PAR_PROC_CAP); | ||
429 | snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n", | ||
430 | proc_caps & AC_PCAP_BENIGN, | ||
431 | (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT); | ||
240 | } | 432 | } |
241 | 433 | ||
434 | static void print_conn_list(struct snd_info_buffer *buffer, | ||
435 | struct hda_codec *codec, hda_nid_t nid, | ||
436 | unsigned int wid_type, hda_nid_t *conn, | ||
437 | int conn_len) | ||
438 | { | ||
439 | int c, curr = -1; | ||
440 | |||
441 | if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | ||
442 | curr = snd_hda_codec_read(codec, nid, 0, | ||
443 | AC_VERB_GET_CONNECT_SEL, 0); | ||
444 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | ||
445 | if (conn_len > 0) { | ||
446 | snd_iprintf(buffer, " "); | ||
447 | for (c = 0; c < conn_len; c++) { | ||
448 | snd_iprintf(buffer, " 0x%02x", conn[c]); | ||
449 | if (c == curr) | ||
450 | snd_iprintf(buffer, "*"); | ||
451 | } | ||
452 | snd_iprintf(buffer, "\n"); | ||
453 | } | ||
454 | } | ||
455 | |||
456 | static void print_realtek_coef(struct snd_info_buffer *buffer, | ||
457 | struct hda_codec *codec, hda_nid_t nid) | ||
458 | { | ||
459 | int coeff = snd_hda_codec_read(codec, nid, 0, | ||
460 | AC_VERB_GET_PROC_COEF, 0); | ||
461 | snd_iprintf(buffer, " Processing Coefficient: 0x%02x\n", coeff); | ||
462 | coeff = snd_hda_codec_read(codec, nid, 0, | ||
463 | AC_VERB_GET_COEF_INDEX, 0); | ||
464 | snd_iprintf(buffer, " Coefficient Index: 0x%02x\n", coeff); | ||
465 | } | ||
466 | |||
467 | static void print_gpio(struct snd_info_buffer *buffer, | ||
468 | struct hda_codec *codec, hda_nid_t nid) | ||
469 | { | ||
470 | unsigned int gpio = | ||
471 | snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); | ||
472 | unsigned int enable, direction, wake, unsol, sticky, data; | ||
473 | int i, max; | ||
474 | snd_iprintf(buffer, "GPIO: io=%d, o=%d, i=%d, " | ||
475 | "unsolicited=%d, wake=%d\n", | ||
476 | gpio & AC_GPIO_IO_COUNT, | ||
477 | (gpio & AC_GPIO_O_COUNT) >> AC_GPIO_O_COUNT_SHIFT, | ||
478 | (gpio & AC_GPIO_I_COUNT) >> AC_GPIO_I_COUNT_SHIFT, | ||
479 | (gpio & AC_GPIO_UNSOLICITED) ? 1 : 0, | ||
480 | (gpio & AC_GPIO_WAKE) ? 1 : 0); | ||
481 | max = gpio & AC_GPIO_IO_COUNT; | ||
482 | enable = snd_hda_codec_read(codec, nid, 0, | ||
483 | AC_VERB_GET_GPIO_MASK, 0); | ||
484 | direction = snd_hda_codec_read(codec, nid, 0, | ||
485 | AC_VERB_GET_GPIO_DIRECTION, 0); | ||
486 | wake = snd_hda_codec_read(codec, nid, 0, | ||
487 | AC_VERB_GET_GPIO_WAKE_MASK, 0); | ||
488 | unsol = snd_hda_codec_read(codec, nid, 0, | ||
489 | AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK, 0); | ||
490 | sticky = snd_hda_codec_read(codec, nid, 0, | ||
491 | AC_VERB_GET_GPIO_STICKY_MASK, 0); | ||
492 | data = snd_hda_codec_read(codec, nid, 0, | ||
493 | AC_VERB_GET_GPIO_DATA, 0); | ||
494 | for (i = 0; i < max; ++i) | ||
495 | snd_iprintf(buffer, | ||
496 | " IO[%d]: enable=%d, dir=%d, wake=%d, " | ||
497 | "sticky=%d, data=%d\n", i, | ||
498 | (enable & (1<<i)) ? 1 : 0, | ||
499 | (direction & (1<<i)) ? 1 : 0, | ||
500 | (wake & (1<<i)) ? 1 : 0, | ||
501 | (sticky & (1<<i)) ? 1 : 0, | ||
502 | (data & (1<<i)) ? 1 : 0); | ||
503 | /* FIXME: add GPO and GPI pin information */ | ||
504 | } | ||
242 | 505 | ||
243 | static void print_codec_info(struct snd_info_entry *entry, | 506 | static void print_codec_info(struct snd_info_entry *entry, |
244 | struct snd_info_buffer *buffer) | 507 | struct snd_info_buffer *buffer) |
@@ -276,14 +539,17 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
276 | snd_hda_power_down(codec); | 539 | snd_hda_power_down(codec); |
277 | return; | 540 | return; |
278 | } | 541 | } |
542 | |||
543 | print_gpio(buffer, codec, codec->afg); | ||
544 | |||
279 | for (i = 0; i < nodes; i++, nid++) { | 545 | for (i = 0; i < nodes; i++, nid++) { |
280 | unsigned int wid_caps = | 546 | unsigned int wid_caps = |
281 | snd_hda_param_read(codec, nid, | 547 | snd_hda_param_read(codec, nid, |
282 | AC_PAR_AUDIO_WIDGET_CAP); | 548 | AC_PAR_AUDIO_WIDGET_CAP); |
283 | unsigned int wid_type = | 549 | unsigned int wid_type = |
284 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 550 | (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
285 | int conn_len = 0; | ||
286 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | 551 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; |
552 | int conn_len = 0; | ||
287 | 553 | ||
288 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, | 554 | snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, |
289 | get_wid_type_name(wid_type), wid_caps); | 555 | get_wid_type_name(wid_type), wid_caps); |
@@ -297,8 +563,18 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
297 | snd_iprintf(buffer, " Amp-In"); | 563 | snd_iprintf(buffer, " Amp-In"); |
298 | if (wid_caps & AC_WCAP_OUT_AMP) | 564 | if (wid_caps & AC_WCAP_OUT_AMP) |
299 | snd_iprintf(buffer, " Amp-Out"); | 565 | snd_iprintf(buffer, " Amp-Out"); |
566 | if (wid_caps & AC_WCAP_STRIPE) | ||
567 | snd_iprintf(buffer, " Stripe"); | ||
568 | if (wid_caps & AC_WCAP_LR_SWAP) | ||
569 | snd_iprintf(buffer, " R/L"); | ||
300 | snd_iprintf(buffer, "\n"); | 570 | snd_iprintf(buffer, "\n"); |
301 | 571 | ||
572 | /* volume knob is a special widget that always have connection | ||
573 | * list | ||
574 | */ | ||
575 | if (wid_type == AC_WID_VOL_KNB) | ||
576 | wid_caps |= AC_WCAP_CONN_LIST; | ||
577 | |||
302 | if (wid_caps & AC_WCAP_CONN_LIST) | 578 | if (wid_caps & AC_WCAP_CONN_LIST) |
303 | conn_len = snd_hda_get_connections(codec, nid, conn, | 579 | conn_len = snd_hda_get_connections(codec, nid, conn, |
304 | HDA_MAX_CONNECTIONS); | 580 | HDA_MAX_CONNECTIONS); |
@@ -318,48 +594,49 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
318 | wid_caps & AC_WCAP_STEREO, 1); | 594 | wid_caps & AC_WCAP_STEREO, 1); |
319 | } | 595 | } |
320 | 596 | ||
321 | if (wid_type == AC_WID_PIN) { | 597 | switch (wid_type) { |
322 | unsigned int pinctls; | 598 | case AC_WID_PIN: { |
323 | print_pin_caps(buffer, codec, nid); | 599 | int supports_vref; |
324 | pinctls = snd_hda_codec_read(codec, nid, 0, | 600 | print_pin_caps(buffer, codec, nid, &supports_vref); |
325 | AC_VERB_GET_PIN_WIDGET_CONTROL, | 601 | print_pin_ctls(buffer, codec, nid, supports_vref); |
326 | 0); | 602 | break; |
327 | snd_iprintf(buffer, " Pin-ctls: 0x%02x:", pinctls); | ||
328 | if (pinctls & AC_PINCTL_IN_EN) | ||
329 | snd_iprintf(buffer, " IN"); | ||
330 | if (pinctls & AC_PINCTL_OUT_EN) | ||
331 | snd_iprintf(buffer, " OUT"); | ||
332 | if (pinctls & AC_PINCTL_HP_EN) | ||
333 | snd_iprintf(buffer, " HP"); | ||
334 | snd_iprintf(buffer, "\n"); | ||
335 | } | 603 | } |
336 | 604 | case AC_WID_VOL_KNB: | |
337 | if ((wid_type == AC_WID_AUD_OUT || wid_type == AC_WID_AUD_IN) && | 605 | print_vol_knob(buffer, codec, nid); |
338 | (wid_caps & AC_WCAP_FORMAT_OVRD)) { | 606 | break; |
339 | snd_iprintf(buffer, " PCM:\n"); | 607 | case AC_WID_AUD_OUT: |
340 | print_pcm_caps(buffer, codec, nid); | 608 | case AC_WID_AUD_IN: |
609 | print_audio_io(buffer, codec, nid, wid_type); | ||
610 | if (wid_caps & AC_WCAP_DIGITAL) | ||
611 | print_digital_conv(buffer, codec, nid); | ||
612 | if (wid_caps & AC_WCAP_FORMAT_OVRD) { | ||
613 | snd_iprintf(buffer, " PCM:\n"); | ||
614 | print_pcm_caps(buffer, codec, nid); | ||
615 | } | ||
616 | break; | ||
341 | } | 617 | } |
342 | 618 | ||
619 | if (wid_caps & AC_WCAP_UNSOL_CAP) | ||
620 | print_unsol_cap(buffer, codec, nid); | ||
621 | |||
343 | if (wid_caps & AC_WCAP_POWER) | 622 | if (wid_caps & AC_WCAP_POWER) |
344 | snd_iprintf(buffer, " Power: 0x%x\n", | 623 | print_power_state(buffer, codec, nid); |
345 | snd_hda_codec_read(codec, nid, 0, | 624 | |
346 | AC_VERB_GET_POWER_STATE, | 625 | if (wid_caps & AC_WCAP_DELAY) |
347 | 0)); | 626 | snd_iprintf(buffer, " Delay: %d samples\n", |
348 | 627 | (wid_caps & AC_WCAP_DELAY) >> | |
349 | if (wid_caps & AC_WCAP_CONN_LIST) { | 628 | AC_WCAP_DELAY_SHIFT); |
350 | int c, curr = -1; | 629 | |
351 | if (conn_len > 1 && wid_type != AC_WID_AUD_MIX) | 630 | if (wid_caps & AC_WCAP_CONN_LIST) |
352 | curr = snd_hda_codec_read(codec, nid, 0, | 631 | print_conn_list(buffer, codec, nid, wid_type, |
353 | AC_VERB_GET_CONNECT_SEL, 0); | 632 | conn, conn_len); |
354 | snd_iprintf(buffer, " Connection: %d\n", conn_len); | 633 | |
355 | snd_iprintf(buffer, " "); | 634 | if (wid_caps & AC_WCAP_PROC_WID) |
356 | for (c = 0; c < conn_len; c++) { | 635 | print_proc_caps(buffer, codec, nid); |
357 | snd_iprintf(buffer, " 0x%02x", conn[c]); | 636 | |
358 | if (c == curr) | 637 | /* NID 0x20 == Realtek Define Registers */ |
359 | snd_iprintf(buffer, "*"); | 638 | if (codec->vendor_id == 0x10ec && nid == 0x20) |
360 | } | 639 | print_realtek_coef(buffer, codec, nid); |
361 | snd_iprintf(buffer, "\n"); | ||
362 | } | ||
363 | } | 640 | } |
364 | snd_hda_power_down(codec); | 641 | snd_hda_power_down(codec); |
365 | } | 642 | } |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 0ee8ae4d4410..19f08846d6fc 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
@@ -79,6 +78,11 @@ struct ad198x_spec { | |||
79 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 78 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
80 | struct hda_loopback_check loopback; | 79 | struct hda_loopback_check loopback; |
81 | #endif | 80 | #endif |
81 | /* for virtual master */ | ||
82 | hda_nid_t vmaster_nid; | ||
83 | u32 vmaster_tlv[4]; | ||
84 | const char **slave_vols; | ||
85 | const char **slave_sws; | ||
82 | }; | 86 | }; |
83 | 87 | ||
84 | /* | 88 | /* |
@@ -126,6 +130,32 @@ static int ad198x_init(struct hda_codec *codec) | |||
126 | return 0; | 130 | return 0; |
127 | } | 131 | } |
128 | 132 | ||
133 | static const char *ad_slave_vols[] = { | ||
134 | "Front Playback Volume", | ||
135 | "Surround Playback Volume", | ||
136 | "Center Playback Volume", | ||
137 | "LFE Playback Volume", | ||
138 | "Side Playback Volume", | ||
139 | "Headphone Playback Volume", | ||
140 | "Mono Playback Volume", | ||
141 | "Speaker Playback Volume", | ||
142 | "IEC958 Playback Volume", | ||
143 | NULL | ||
144 | }; | ||
145 | |||
146 | static const char *ad_slave_sws[] = { | ||
147 | "Front Playback Switch", | ||
148 | "Surround Playback Switch", | ||
149 | "Center Playback Switch", | ||
150 | "LFE Playback Switch", | ||
151 | "Side Playback Switch", | ||
152 | "Headphone Playback Switch", | ||
153 | "Mono Playback Switch", | ||
154 | "Speaker Playback Switch", | ||
155 | "IEC958 Playback Switch", | ||
156 | NULL | ||
157 | }; | ||
158 | |||
129 | static int ad198x_build_controls(struct hda_codec *codec) | 159 | static int ad198x_build_controls(struct hda_codec *codec) |
130 | { | 160 | { |
131 | struct ad198x_spec *spec = codec->spec; | 161 | struct ad198x_spec *spec = codec->spec; |
@@ -147,6 +177,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
147 | if (err < 0) | 177 | if (err < 0) |
148 | return err; | 178 | return err; |
149 | } | 179 | } |
180 | |||
181 | /* if we have no master control, let's create it */ | ||
182 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
183 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
184 | HDA_OUTPUT, spec->vmaster_tlv); | ||
185 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
186 | spec->vmaster_tlv, | ||
187 | (spec->slave_vols ? | ||
188 | spec->slave_vols : ad_slave_vols)); | ||
189 | if (err < 0) | ||
190 | return err; | ||
191 | } | ||
192 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
193 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
194 | NULL, | ||
195 | (spec->slave_sws ? | ||
196 | spec->slave_sws : ad_slave_sws)); | ||
197 | if (err < 0) | ||
198 | return err; | ||
199 | } | ||
200 | |||
150 | return 0; | 201 | return 0; |
151 | } | 202 | } |
152 | 203 | ||
@@ -370,7 +421,7 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, | |||
370 | int invert = (kcontrol->private_value >> 8) & 1; | 421 | int invert = (kcontrol->private_value >> 8) & 1; |
371 | hda_nid_t nid = kcontrol->private_value & 0xff; | 422 | hda_nid_t nid = kcontrol->private_value & 0xff; |
372 | unsigned int eapd; | 423 | unsigned int eapd; |
373 | eapd = ucontrol->value.integer.value[0]; | 424 | eapd = !!ucontrol->value.integer.value[0]; |
374 | if (invert) | 425 | if (invert) |
375 | eapd = !eapd; | 426 | eapd = !eapd; |
376 | if (eapd == spec->cur_eapd) | 427 | if (eapd == spec->cur_eapd) |
@@ -833,27 +884,29 @@ static const char *ad1986a_models[AD1986A_MODELS] = { | |||
833 | 884 | ||
834 | static struct snd_pci_quirk ad1986a_cfg_tbl[] = { | 885 | static struct snd_pci_quirk ad1986a_cfg_tbl[] = { |
835 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), | 886 | SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), |
836 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
837 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), | 887 | SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), |
838 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
839 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), | 888 | SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), |
889 | SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), | ||
840 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), | 890 | SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), |
841 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), | 891 | SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), |
842 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), | 892 | SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), |
843 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), | 893 | SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), |
894 | SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), | ||
844 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), | 895 | SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), |
845 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), | 896 | SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), |
846 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), | 897 | SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), |
847 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), | 898 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), |
848 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), | 899 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), |
849 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), | 900 | SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), |
901 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), | ||
902 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD), | ||
850 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), | 903 | SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), |
851 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), | 904 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), |
852 | SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), | 905 | SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_LAPTOP_EAPD), |
853 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), | 906 | SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_LAPTOP_EAPD), |
854 | SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), | 907 | SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_LAPTOP_EAPD), |
855 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
856 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), | 908 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), |
909 | SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), | ||
857 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), | 910 | SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), |
858 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), | 911 | SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), |
859 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), | 912 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), |
@@ -872,6 +925,13 @@ static struct hda_amp_list ad1986a_loopbacks[] = { | |||
872 | }; | 925 | }; |
873 | #endif | 926 | #endif |
874 | 927 | ||
928 | static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) | ||
929 | { | ||
930 | unsigned int conf = snd_hda_codec_read(codec, nid, 0, | ||
931 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
932 | return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; | ||
933 | } | ||
934 | |||
875 | static int patch_ad1986a(struct hda_codec *codec) | 935 | static int patch_ad1986a(struct hda_codec *codec) |
876 | { | 936 | { |
877 | struct ad198x_spec *spec; | 937 | struct ad198x_spec *spec; |
@@ -898,6 +958,7 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
898 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 958 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
899 | spec->loopback.amplist = ad1986a_loopbacks; | 959 | spec->loopback.amplist = ad1986a_loopbacks; |
900 | #endif | 960 | #endif |
961 | spec->vmaster_nid = 0x1b; | ||
901 | 962 | ||
902 | codec->patch_ops = ad198x_patch_ops; | 963 | codec->patch_ops = ad198x_patch_ops; |
903 | 964 | ||
@@ -930,7 +991,8 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
930 | spec->multiout.max_channels = 2; | 991 | spec->multiout.max_channels = 2; |
931 | spec->multiout.num_dacs = 1; | 992 | spec->multiout.num_dacs = 1; |
932 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | 993 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; |
933 | spec->multiout.dig_out_nid = 0; | 994 | if (!is_jack_available(codec, 0x25)) |
995 | spec->multiout.dig_out_nid = 0; | ||
934 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 996 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
935 | break; | 997 | break; |
936 | case AD1986A_LAPTOP_AUTOMUTE: | 998 | case AD1986A_LAPTOP_AUTOMUTE: |
@@ -941,7 +1003,8 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
941 | spec->multiout.max_channels = 2; | 1003 | spec->multiout.max_channels = 2; |
942 | spec->multiout.num_dacs = 1; | 1004 | spec->multiout.num_dacs = 1; |
943 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; | 1005 | spec->multiout.dac_nids = ad1986a_laptop_dac_nids; |
944 | spec->multiout.dig_out_nid = 0; | 1006 | if (!is_jack_available(codec, 0x25)) |
1007 | spec->multiout.dig_out_nid = 0; | ||
945 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; | 1008 | spec->input_mux = &ad1986a_laptop_eapd_capture_source; |
946 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; | 1009 | codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; |
947 | codec->patch_ops.init = ad1986a_hp_init; | 1010 | codec->patch_ops.init = ad1986a_hp_init; |
@@ -957,6 +1020,14 @@ static int patch_ad1986a(struct hda_codec *codec) | |||
957 | break; | 1020 | break; |
958 | } | 1021 | } |
959 | 1022 | ||
1023 | /* AD1986A has a hardware problem that it can't share a stream | ||
1024 | * with multiple output pins. The copy of front to surrounds | ||
1025 | * causes noisy or silent outputs at a certain timing, e.g. | ||
1026 | * changing the volume. | ||
1027 | * So, let's disable the shared stream. | ||
1028 | */ | ||
1029 | spec->multiout.no_share_stream = 1; | ||
1030 | |||
960 | return 0; | 1031 | return 0; |
961 | } | 1032 | } |
962 | 1033 | ||
@@ -1012,6 +1083,8 @@ static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1012 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1083 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1013 | struct ad198x_spec *spec = codec->spec; | 1084 | struct ad198x_spec *spec = codec->spec; |
1014 | 1085 | ||
1086 | if (ucontrol->value.enumerated.item[0] > 1) | ||
1087 | return -EINVAL; | ||
1015 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { | 1088 | if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { |
1016 | spec->spdif_route = ucontrol->value.enumerated.item[0]; | 1089 | spec->spdif_route = ucontrol->value.enumerated.item[0]; |
1017 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, | 1090 | snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, |
@@ -1130,6 +1203,7 @@ static int patch_ad1983(struct hda_codec *codec) | |||
1130 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1203 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1131 | spec->loopback.amplist = ad1983_loopbacks; | 1204 | spec->loopback.amplist = ad1983_loopbacks; |
1132 | #endif | 1205 | #endif |
1206 | spec->vmaster_nid = 0x05; | ||
1133 | 1207 | ||
1134 | codec->patch_ops = ad198x_patch_ops; | 1208 | codec->patch_ops = ad198x_patch_ops; |
1135 | 1209 | ||
@@ -1488,14 +1562,14 @@ static const char *ad1981_models[AD1981_MODELS] = { | |||
1488 | }; | 1562 | }; |
1489 | 1563 | ||
1490 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { | 1564 | static struct snd_pci_quirk ad1981_cfg_tbl[] = { |
1565 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | ||
1491 | /* All HP models */ | 1566 | /* All HP models */ |
1492 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), | 1567 | SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP), |
1493 | /* HP nx6320 (reversed SSID, H/W bug) */ | 1568 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), |
1494 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), | ||
1495 | /* Lenovo Thinkpad T60/X60/Z6xx */ | 1569 | /* Lenovo Thinkpad T60/X60/Z6xx */ |
1496 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), | 1570 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD), |
1497 | SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD), | 1571 | /* HP nx6320 (reversed SSID, H/W bug) */ |
1498 | SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), | 1572 | SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), |
1499 | {} | 1573 | {} |
1500 | }; | 1574 | }; |
1501 | 1575 | ||
@@ -1526,6 +1600,7 @@ static int patch_ad1981(struct hda_codec *codec) | |||
1526 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1600 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1527 | spec->loopback.amplist = ad1981_loopbacks; | 1601 | spec->loopback.amplist = ad1981_loopbacks; |
1528 | #endif | 1602 | #endif |
1603 | spec->vmaster_nid = 0x05; | ||
1529 | 1604 | ||
1530 | codec->patch_ops = ad198x_patch_ops; | 1605 | codec->patch_ops = ad198x_patch_ops; |
1531 | 1606 | ||
@@ -1900,7 +1975,6 @@ static struct snd_kcontrol_new ad1988_capture_mixers[] = { | |||
1900 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1975 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1901 | /* The multiple "Capture Source" controls confuse alsamixer | 1976 | /* The multiple "Capture Source" controls confuse alsamixer |
1902 | * So call somewhat different.. | 1977 | * So call somewhat different.. |
1903 | * FIXME: the controls appear in the "playback" view! | ||
1904 | */ | 1978 | */ |
1905 | /* .name = "Capture Source", */ | 1979 | /* .name = "Capture Source", */ |
1906 | .name = "Input Source", | 1980 | .name = "Input Source", |
@@ -1957,6 +2031,8 @@ static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, | |||
1957 | int change; | 2031 | int change; |
1958 | 2032 | ||
1959 | val = ucontrol->value.enumerated.item[0]; | 2033 | val = ucontrol->value.enumerated.item[0]; |
2034 | if (val > 3) | ||
2035 | return -EINVAL; | ||
1960 | if (!val) { | 2036 | if (!val) { |
1961 | sel = snd_hda_codec_read(codec, 0x1d, 0, | 2037 | sel = snd_hda_codec_read(codec, 0x1d, 0, |
1962 | AC_VERB_GET_AMP_GAIN_MUTE, | 2038 | AC_VERB_GET_AMP_GAIN_MUTE, |
@@ -2071,6 +2147,8 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { | |||
2071 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2147 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
2072 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | 2148 | {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, |
2073 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, | 2149 | {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, |
2150 | /* Analog CD Input */ | ||
2151 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2074 | 2152 | ||
2075 | { } | 2153 | { } |
2076 | }; | 2154 | }; |
@@ -2712,8 +2790,8 @@ static const char *ad1988_models[AD1988_MODEL_LAST] = { | |||
2712 | }; | 2790 | }; |
2713 | 2791 | ||
2714 | static struct snd_pci_quirk ad1988_cfg_tbl[] = { | 2792 | static struct snd_pci_quirk ad1988_cfg_tbl[] = { |
2715 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
2716 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), | 2793 | SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), |
2794 | SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), | ||
2717 | {} | 2795 | {} |
2718 | }; | 2796 | }; |
2719 | 2797 | ||
@@ -2835,6 +2913,7 @@ static int patch_ad1988(struct hda_codec *codec) | |||
2835 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2913 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2836 | spec->loopback.amplist = ad1988_loopbacks; | 2914 | spec->loopback.amplist = ad1988_loopbacks; |
2837 | #endif | 2915 | #endif |
2916 | spec->vmaster_nid = 0x04; | ||
2838 | 2917 | ||
2839 | return 0; | 2918 | return 0; |
2840 | } | 2919 | } |
@@ -2911,7 +2990,6 @@ static struct snd_kcontrol_new ad1884_base_mixers[] = { | |||
2911 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2990 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2912 | /* The multiple "Capture Source" controls confuse alsamixer | 2991 | /* The multiple "Capture Source" controls confuse alsamixer |
2913 | * So call somewhat different.. | 2992 | * So call somewhat different.. |
2914 | * FIXME: the controls appear in the "playback" view! | ||
2915 | */ | 2993 | */ |
2916 | /* .name = "Capture Source", */ | 2994 | /* .name = "Capture Source", */ |
2917 | .name = "Input Source", | 2995 | .name = "Input Source", |
@@ -3001,6 +3079,20 @@ static struct hda_amp_list ad1884_loopbacks[] = { | |||
3001 | }; | 3079 | }; |
3002 | #endif | 3080 | #endif |
3003 | 3081 | ||
3082 | static const char *ad1884_slave_vols[] = { | ||
3083 | "PCM Playback Volume", | ||
3084 | "Mic Playback Volume", | ||
3085 | "Mono Playback Volume", | ||
3086 | "Front Mic Playback Volume", | ||
3087 | "Mic Playback Volume", | ||
3088 | "CD Playback Volume", | ||
3089 | "Internal Mic Playback Volume", | ||
3090 | "Docking Mic Playback Volume" | ||
3091 | "Beep Playback Volume", | ||
3092 | "IEC958 Playback Volume", | ||
3093 | NULL | ||
3094 | }; | ||
3095 | |||
3004 | static int patch_ad1884(struct hda_codec *codec) | 3096 | static int patch_ad1884(struct hda_codec *codec) |
3005 | { | 3097 | { |
3006 | struct ad198x_spec *spec; | 3098 | struct ad198x_spec *spec; |
@@ -3028,6 +3120,9 @@ static int patch_ad1884(struct hda_codec *codec) | |||
3028 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3120 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3029 | spec->loopback.amplist = ad1884_loopbacks; | 3121 | spec->loopback.amplist = ad1884_loopbacks; |
3030 | #endif | 3122 | #endif |
3123 | spec->vmaster_nid = 0x04; | ||
3124 | /* we need to cover all playback volumes */ | ||
3125 | spec->slave_vols = ad1884_slave_vols; | ||
3031 | 3126 | ||
3032 | codec->patch_ops = ad198x_patch_ops; | 3127 | codec->patch_ops = ad198x_patch_ops; |
3033 | 3128 | ||
@@ -3046,6 +3141,20 @@ static struct hda_input_mux ad1984_thinkpad_capture_source = { | |||
3046 | }, | 3141 | }, |
3047 | }; | 3142 | }; |
3048 | 3143 | ||
3144 | |||
3145 | /* | ||
3146 | * Dell Precision T3400 | ||
3147 | */ | ||
3148 | static struct hda_input_mux ad1984_dell_desktop_capture_source = { | ||
3149 | .num_items = 3, | ||
3150 | .items = { | ||
3151 | { "Front Mic", 0x0 }, | ||
3152 | { "Line-In", 0x1 }, | ||
3153 | { "Mix", 0x3 }, | ||
3154 | }, | ||
3155 | }; | ||
3156 | |||
3157 | |||
3049 | static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | 3158 | static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { |
3050 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | 3159 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), |
3051 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ | 3160 | /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ |
@@ -3070,7 +3179,6 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | |||
3070 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3179 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3071 | /* The multiple "Capture Source" controls confuse alsamixer | 3180 | /* The multiple "Capture Source" controls confuse alsamixer |
3072 | * So call somewhat different.. | 3181 | * So call somewhat different.. |
3073 | * FIXME: the controls appear in the "playback" view! | ||
3074 | */ | 3182 | */ |
3075 | /* .name = "Capture Source", */ | 3183 | /* .name = "Capture Source", */ |
3076 | .name = "Input Source", | 3184 | .name = "Input Source", |
@@ -3079,6 +3187,16 @@ static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { | |||
3079 | .get = ad198x_mux_enum_get, | 3187 | .get = ad198x_mux_enum_get, |
3080 | .put = ad198x_mux_enum_put, | 3188 | .put = ad198x_mux_enum_put, |
3081 | }, | 3189 | }, |
3190 | /* SPDIF controls */ | ||
3191 | HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), | ||
3192 | { | ||
3193 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3194 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
3195 | /* identical with ad1983 */ | ||
3196 | .info = ad1983_spdif_route_info, | ||
3197 | .get = ad1983_spdif_route_get, | ||
3198 | .put = ad1983_spdif_route_put, | ||
3199 | }, | ||
3082 | { } /* end */ | 3200 | { } /* end */ |
3083 | }; | 3201 | }; |
3084 | 3202 | ||
@@ -3096,6 +3214,44 @@ static struct hda_verb ad1984_thinkpad_init_verbs[] = { | |||
3096 | { } /* end */ | 3214 | { } /* end */ |
3097 | }; | 3215 | }; |
3098 | 3216 | ||
3217 | /* | ||
3218 | * Dell Precision T3400 | ||
3219 | */ | ||
3220 | static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { | ||
3221 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), | ||
3222 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
3223 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
3224 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3225 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), | ||
3226 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), | ||
3227 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), | ||
3228 | HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), | ||
3229 | HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), | ||
3230 | /* | ||
3231 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT), | ||
3232 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT), | ||
3233 | */ | ||
3234 | HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT), | ||
3235 | HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT), | ||
3236 | HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
3237 | HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), | ||
3238 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3239 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), | ||
3240 | { | ||
3241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3242 | /* The multiple "Capture Source" controls confuse alsamixer | ||
3243 | * So call somewhat different.. | ||
3244 | */ | ||
3245 | /* .name = "Capture Source", */ | ||
3246 | .name = "Input Source", | ||
3247 | .count = 2, | ||
3248 | .info = ad198x_mux_enum_info, | ||
3249 | .get = ad198x_mux_enum_get, | ||
3250 | .put = ad198x_mux_enum_put, | ||
3251 | }, | ||
3252 | { } /* end */ | ||
3253 | }; | ||
3254 | |||
3099 | /* Digial MIC ADC NID 0x05 + 0x06 */ | 3255 | /* Digial MIC ADC NID 0x05 + 0x06 */ |
3100 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, | 3256 | static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, |
3101 | struct hda_codec *codec, | 3257 | struct hda_codec *codec, |
@@ -3149,17 +3305,20 @@ static int ad1984_build_pcms(struct hda_codec *codec) | |||
3149 | enum { | 3305 | enum { |
3150 | AD1984_BASIC, | 3306 | AD1984_BASIC, |
3151 | AD1984_THINKPAD, | 3307 | AD1984_THINKPAD, |
3308 | AD1984_DELL_DESKTOP, | ||
3152 | AD1984_MODELS | 3309 | AD1984_MODELS |
3153 | }; | 3310 | }; |
3154 | 3311 | ||
3155 | static const char *ad1984_models[AD1984_MODELS] = { | 3312 | static const char *ad1984_models[AD1984_MODELS] = { |
3156 | [AD1984_BASIC] = "basic", | 3313 | [AD1984_BASIC] = "basic", |
3157 | [AD1984_THINKPAD] = "thinkpad", | 3314 | [AD1984_THINKPAD] = "thinkpad", |
3315 | [AD1984_DELL_DESKTOP] = "dell_desktop", | ||
3158 | }; | 3316 | }; |
3159 | 3317 | ||
3160 | static struct snd_pci_quirk ad1984_cfg_tbl[] = { | 3318 | static struct snd_pci_quirk ad1984_cfg_tbl[] = { |
3161 | /* Lenovo Thinkpad T61/X61 */ | 3319 | /* Lenovo Thinkpad T61/X61 */ |
3162 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), | 3320 | SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD), |
3321 | SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), | ||
3163 | {} | 3322 | {} |
3164 | }; | 3323 | }; |
3165 | 3324 | ||
@@ -3181,11 +3340,16 @@ static int patch_ad1984(struct hda_codec *codec) | |||
3181 | codec->patch_ops.build_pcms = ad1984_build_pcms; | 3340 | codec->patch_ops.build_pcms = ad1984_build_pcms; |
3182 | break; | 3341 | break; |
3183 | case AD1984_THINKPAD: | 3342 | case AD1984_THINKPAD: |
3184 | spec->multiout.dig_out_nid = 0; | 3343 | spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; |
3185 | spec->input_mux = &ad1984_thinkpad_capture_source; | 3344 | spec->input_mux = &ad1984_thinkpad_capture_source; |
3186 | spec->mixers[0] = ad1984_thinkpad_mixers; | 3345 | spec->mixers[0] = ad1984_thinkpad_mixers; |
3187 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; | 3346 | spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; |
3188 | break; | 3347 | break; |
3348 | case AD1984_DELL_DESKTOP: | ||
3349 | spec->multiout.dig_out_nid = 0; | ||
3350 | spec->input_mux = &ad1984_dell_desktop_capture_source; | ||
3351 | spec->mixers[0] = ad1984_dell_desktop_mixers; | ||
3352 | break; | ||
3189 | } | 3353 | } |
3190 | return 0; | 3354 | return 0; |
3191 | } | 3355 | } |
@@ -3259,7 +3423,6 @@ static struct snd_kcontrol_new ad1882_base_mixers[] = { | |||
3259 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3423 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3260 | /* The multiple "Capture Source" controls confuse alsamixer | 3424 | /* The multiple "Capture Source" controls confuse alsamixer |
3261 | * So call somewhat different.. | 3425 | * So call somewhat different.. |
3262 | * FIXME: the controls appear in the "playback" view! | ||
3263 | */ | 3426 | */ |
3264 | /* .name = "Capture Source", */ | 3427 | /* .name = "Capture Source", */ |
3265 | .name = "Input Source", | 3428 | .name = "Input Source", |
@@ -3460,6 +3623,7 @@ static int patch_ad1882(struct hda_codec *codec) | |||
3460 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3623 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3461 | spec->loopback.amplist = ad1882_loopbacks; | 3624 | spec->loopback.amplist = ad1882_loopbacks; |
3462 | #endif | 3625 | #endif |
3626 | spec->vmaster_nid = 0x04; | ||
3463 | 3627 | ||
3464 | codec->patch_ops = ad198x_patch_ops; | 3628 | codec->patch_ops = ad198x_patch_ops; |
3465 | 3629 | ||
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c index fbb8969dc559..9a8bb4ce3f8d 100644 --- a/sound/pci/hda/patch_atihdmi.c +++ b/sound/pci/hda/patch_atihdmi.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
@@ -158,6 +157,6 @@ struct hda_codec_preset snd_hda_preset_atihdmi[] = { | |||
158 | { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | 157 | { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, |
159 | { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | 158 | { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, |
160 | { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, | 159 | { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi }, |
161 | { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi }, | 160 | { .id = 0x1002aa01, .name = "ATI R6xx HDMI", .patch = patch_atihdmi }, |
162 | {} /* terminator */ | 161 | {} /* terminator */ |
163 | }; | 162 | }; |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 6c54793bf424..3d6097ba1d68 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
@@ -186,7 +185,6 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { | |||
186 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 185 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
187 | /* The multiple "Capture Source" controls confuse alsamixer | 186 | /* The multiple "Capture Source" controls confuse alsamixer |
188 | * So call somewhat different.. | 187 | * So call somewhat different.. |
189 | * FIXME: the controls appear in the "playback" view! | ||
190 | */ | 188 | */ |
191 | /* .name = "Capture Source", */ | 189 | /* .name = "Capture Source", */ |
192 | .name = "Input Source", | 190 | .name = "Input Source", |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6aa073986747..f6dd51cda7b2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
@@ -65,6 +64,11 @@ struct conexant_spec { | |||
65 | hda_nid_t *adc_nids; | 64 | hda_nid_t *adc_nids; |
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 65 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
67 | 66 | ||
67 | unsigned int cur_adc_idx; | ||
68 | hda_nid_t cur_adc; | ||
69 | unsigned int cur_adc_stream_tag; | ||
70 | unsigned int cur_adc_format; | ||
71 | |||
68 | /* capture source */ | 72 | /* capture source */ |
69 | const struct hda_input_mux *input_mux; | 73 | const struct hda_input_mux *input_mux; |
70 | hda_nid_t *capsrc_nids; | 74 | hda_nid_t *capsrc_nids; |
@@ -218,6 +222,41 @@ static struct hda_pcm_stream conexant_pcm_digital_capture = { | |||
218 | /* NID is set in alc_build_pcms */ | 222 | /* NID is set in alc_build_pcms */ |
219 | }; | 223 | }; |
220 | 224 | ||
225 | static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
226 | struct hda_codec *codec, | ||
227 | unsigned int stream_tag, | ||
228 | unsigned int format, | ||
229 | struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | struct conexant_spec *spec = codec->spec; | ||
232 | spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
233 | spec->cur_adc_stream_tag = stream_tag; | ||
234 | spec->cur_adc_format = format; | ||
235 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
240 | struct hda_codec *codec, | ||
241 | struct snd_pcm_substream *substream) | ||
242 | { | ||
243 | struct conexant_spec *spec = codec->spec; | ||
244 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
245 | spec->cur_adc = 0; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static struct hda_pcm_stream cx5051_pcm_analog_capture = { | ||
250 | .substreams = 1, | ||
251 | .channels_min = 2, | ||
252 | .channels_max = 2, | ||
253 | .nid = 0, /* fill later */ | ||
254 | .ops = { | ||
255 | .prepare = cx5051_capture_pcm_prepare, | ||
256 | .cleanup = cx5051_capture_pcm_cleanup | ||
257 | }, | ||
258 | }; | ||
259 | |||
221 | static int conexant_build_pcms(struct hda_codec *codec) | 260 | static int conexant_build_pcms(struct hda_codec *codec) |
222 | { | 261 | { |
223 | struct conexant_spec *spec = codec->spec; | 262 | struct conexant_spec *spec = codec->spec; |
@@ -232,7 +271,12 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
232 | spec->multiout.max_channels; | 271 | spec->multiout.max_channels; |
233 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 272 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
234 | spec->multiout.dac_nids[0]; | 273 | spec->multiout.dac_nids[0]; |
235 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; | 274 | if (codec->vendor_id == 0x14f15051) |
275 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
276 | cx5051_pcm_analog_capture; | ||
277 | else | ||
278 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
279 | conexant_pcm_analog_capture; | ||
236 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | 280 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; |
237 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 281 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
238 | 282 | ||
@@ -373,7 +417,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, | |||
373 | hda_nid_t nid = kcontrol->private_value & 0xff; | 417 | hda_nid_t nid = kcontrol->private_value & 0xff; |
374 | unsigned int eapd; | 418 | unsigned int eapd; |
375 | 419 | ||
376 | eapd = ucontrol->value.integer.value[0]; | 420 | eapd = !!ucontrol->value.integer.value[0]; |
377 | if (invert) | 421 | if (invert) |
378 | eapd = !eapd; | 422 | eapd = !eapd; |
379 | if (eapd == spec->cur_eapd) | 423 | if (eapd == spec->cur_eapd) |
@@ -454,7 +498,16 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
454 | .num_items = 2, | 498 | .num_items = 2, |
455 | .items = { | 499 | .items = { |
456 | { "IntMic", 0x1 }, | 500 | { "IntMic", 0x1 }, |
457 | { "LineIn", 0x2 }, | 501 | { "ExtMic", 0x2 }, |
502 | } | ||
503 | }; | ||
504 | |||
505 | static struct hda_input_mux cxt5045_capture_source_benq = { | ||
506 | .num_items = 3, | ||
507 | .items = { | ||
508 | { "IntMic", 0x1 }, | ||
509 | { "ExtMic", 0x2 }, | ||
510 | { "LineIn", 0x3 }, | ||
458 | } | 511 | } |
459 | }; | 512 | }; |
460 | 513 | ||
@@ -577,6 +630,15 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
577 | {} | 630 | {} |
578 | }; | 631 | }; |
579 | 632 | ||
633 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | ||
634 | HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), | ||
635 | HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), | ||
636 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), | ||
637 | HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), | ||
638 | |||
639 | {} | ||
640 | }; | ||
641 | |||
580 | static struct hda_verb cxt5045_init_verbs[] = { | 642 | static struct hda_verb cxt5045_init_verbs[] = { |
581 | /* Line in, Mic */ | 643 | /* Line in, Mic */ |
582 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 644 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
@@ -602,6 +664,30 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
602 | { } /* end */ | 664 | { } /* end */ |
603 | }; | 665 | }; |
604 | 666 | ||
667 | static struct hda_verb cxt5045_benq_init_verbs[] = { | ||
668 | /* Int Mic, Mic */ | ||
669 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
670 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
671 | /* Line In,HP, Amp */ | ||
672 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
673 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
674 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
675 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
676 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
677 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
678 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
679 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
680 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
681 | /* Record selector: Int mic */ | ||
682 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
683 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, | ||
684 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||
685 | /* SPDIF route: PCM */ | ||
686 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
687 | /* EAPD */ | ||
688 | {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
689 | { } /* end */ | ||
690 | }; | ||
605 | 691 | ||
606 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { | 692 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { |
607 | /* pin sensing on HP jack */ | 693 | /* pin sensing on HP jack */ |
@@ -740,8 +826,10 @@ static int cxt5045_init(struct hda_codec *codec) | |||
740 | 826 | ||
741 | 827 | ||
742 | enum { | 828 | enum { |
743 | CXT5045_LAPTOP, /* Laptops w/ EAPD support */ | 829 | CXT5045_LAPTOP_HPSENSE, |
744 | CXT5045_FUJITSU, /* Laptops w/ EAPD support */ | 830 | CXT5045_LAPTOP_MICSENSE, |
831 | CXT5045_LAPTOP_HPMICSENSE, | ||
832 | CXT5045_BENQ, | ||
745 | #ifdef CONFIG_SND_DEBUG | 833 | #ifdef CONFIG_SND_DEBUG |
746 | CXT5045_TEST, | 834 | CXT5045_TEST, |
747 | #endif | 835 | #endif |
@@ -749,23 +837,35 @@ enum { | |||
749 | }; | 837 | }; |
750 | 838 | ||
751 | static const char *cxt5045_models[CXT5045_MODELS] = { | 839 | static const char *cxt5045_models[CXT5045_MODELS] = { |
752 | [CXT5045_LAPTOP] = "laptop", | 840 | [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", |
753 | [CXT5045_FUJITSU] = "fujitsu", | 841 | [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", |
842 | [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", | ||
843 | [CXT5045_BENQ] = "benq", | ||
754 | #ifdef CONFIG_SND_DEBUG | 844 | #ifdef CONFIG_SND_DEBUG |
755 | [CXT5045_TEST] = "test", | 845 | [CXT5045_TEST] = "test", |
756 | #endif | 846 | #endif |
757 | }; | 847 | }; |
758 | 848 | ||
759 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | 849 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { |
760 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), | 850 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE), |
761 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP), | 851 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
762 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP), | 852 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE), |
763 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP), | 853 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE), |
764 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP), | 854 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE), |
765 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP), | 855 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
766 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU), | 856 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), |
767 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP), | 857 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE), |
768 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP), | 858 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), |
859 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | ||
860 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | ||
861 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), | ||
862 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), | ||
863 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
864 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
865 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
866 | SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
867 | SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
868 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), | ||
769 | {} | 869 | {} |
770 | }; | 870 | }; |
771 | 871 | ||
@@ -803,7 +903,7 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
803 | cxt5045_models, | 903 | cxt5045_models, |
804 | cxt5045_cfg_tbl); | 904 | cxt5045_cfg_tbl); |
805 | switch (board_config) { | 905 | switch (board_config) { |
806 | case CXT5045_LAPTOP: | 906 | case CXT5045_LAPTOP_HPSENSE: |
807 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | 907 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; |
808 | spec->input_mux = &cxt5045_capture_source; | 908 | spec->input_mux = &cxt5045_capture_source; |
809 | spec->num_init_verbs = 2; | 909 | spec->num_init_verbs = 2; |
@@ -811,20 +911,53 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
811 | spec->mixers[0] = cxt5045_mixers; | 911 | spec->mixers[0] = cxt5045_mixers; |
812 | codec->patch_ops.init = cxt5045_init; | 912 | codec->patch_ops.init = cxt5045_init; |
813 | break; | 913 | break; |
814 | case CXT5045_FUJITSU: | 914 | case CXT5045_LAPTOP_MICSENSE: |
815 | spec->input_mux = &cxt5045_capture_source; | 915 | spec->input_mux = &cxt5045_capture_source; |
816 | spec->num_init_verbs = 2; | 916 | spec->num_init_verbs = 2; |
817 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; | 917 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; |
818 | spec->mixers[0] = cxt5045_mixers; | 918 | spec->mixers[0] = cxt5045_mixers; |
819 | codec->patch_ops.init = cxt5045_init; | 919 | codec->patch_ops.init = cxt5045_init; |
820 | break; | 920 | break; |
921 | default: | ||
922 | case CXT5045_LAPTOP_HPMICSENSE: | ||
923 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
924 | spec->input_mux = &cxt5045_capture_source; | ||
925 | spec->num_init_verbs = 3; | ||
926 | spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; | ||
927 | spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; | ||
928 | spec->mixers[0] = cxt5045_mixers; | ||
929 | codec->patch_ops.init = cxt5045_init; | ||
930 | break; | ||
931 | case CXT5045_BENQ: | ||
932 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
933 | spec->input_mux = &cxt5045_capture_source_benq; | ||
934 | spec->num_init_verbs = 1; | ||
935 | spec->init_verbs[0] = cxt5045_benq_init_verbs; | ||
936 | spec->mixers[0] = cxt5045_mixers; | ||
937 | spec->mixers[1] = cxt5045_benq_mixers; | ||
938 | spec->num_mixers = 2; | ||
939 | codec->patch_ops.init = cxt5045_init; | ||
940 | break; | ||
821 | #ifdef CONFIG_SND_DEBUG | 941 | #ifdef CONFIG_SND_DEBUG |
822 | case CXT5045_TEST: | 942 | case CXT5045_TEST: |
823 | spec->input_mux = &cxt5045_test_capture_source; | 943 | spec->input_mux = &cxt5045_test_capture_source; |
824 | spec->mixers[0] = cxt5045_test_mixer; | 944 | spec->mixers[0] = cxt5045_test_mixer; |
825 | spec->init_verbs[0] = cxt5045_test_init_verbs; | 945 | spec->init_verbs[0] = cxt5045_test_init_verbs; |
946 | break; | ||
947 | |||
826 | #endif | 948 | #endif |
827 | } | 949 | } |
950 | |||
951 | /* | ||
952 | * Fix max PCM level to 0 dB | ||
953 | * (originall it has 0x2b steps with 0dB offset 0x14) | ||
954 | */ | ||
955 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | ||
956 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | ||
957 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
958 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
959 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
960 | |||
828 | return 0; | 961 | return 0; |
829 | } | 962 | } |
830 | 963 | ||
@@ -933,13 +1066,13 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) | |||
933 | static void cxt5047_hp_automic(struct hda_codec *codec) | 1066 | static void cxt5047_hp_automic(struct hda_codec *codec) |
934 | { | 1067 | { |
935 | static struct hda_verb mic_jack_on[] = { | 1068 | static struct hda_verb mic_jack_on[] = { |
936 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1069 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
937 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1070 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
938 | {} | 1071 | {} |
939 | }; | 1072 | }; |
940 | static struct hda_verb mic_jack_off[] = { | 1073 | static struct hda_verb mic_jack_off[] = { |
941 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1074 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
942 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1075 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
943 | {} | 1076 | {} |
944 | }; | 1077 | }; |
945 | unsigned int present; | 1078 | unsigned int present; |
@@ -956,8 +1089,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec) | |||
956 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, | 1089 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, |
957 | unsigned int res) | 1090 | unsigned int res) |
958 | { | 1091 | { |
959 | res >>= 26; | 1092 | switch (res >> 26) { |
960 | switch (res) { | ||
961 | case CONEXANT_HP_EVENT: | 1093 | case CONEXANT_HP_EVENT: |
962 | cxt5047_hp_automute(codec); | 1094 | cxt5047_hp_automute(codec); |
963 | break; | 1095 | break; |
@@ -1166,6 +1298,17 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1166 | .get = conexant_mux_enum_get, | 1298 | .get = conexant_mux_enum_get, |
1167 | .put = conexant_mux_enum_put, | 1299 | .put = conexant_mux_enum_put, |
1168 | }, | 1300 | }, |
1301 | HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), | ||
1302 | HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), | ||
1303 | HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), | ||
1304 | HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), | ||
1305 | HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), | ||
1306 | HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), | ||
1307 | HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), | ||
1308 | HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), | ||
1309 | HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), | ||
1310 | HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), | ||
1311 | |||
1169 | { } /* end */ | 1312 | { } /* end */ |
1170 | }; | 1313 | }; |
1171 | 1314 | ||
@@ -1255,9 +1398,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = { | |||
1255 | 1398 | ||
1256 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | 1399 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { |
1257 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), | 1400 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), |
1401 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1258 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), | 1402 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), |
1259 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), | 1403 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), |
1260 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1261 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), | 1404 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), |
1262 | {} | 1405 | {} |
1263 | }; | 1406 | }; |
@@ -1324,10 +1467,260 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1324 | return 0; | 1467 | return 0; |
1325 | } | 1468 | } |
1326 | 1469 | ||
1470 | /* Conexant 5051 specific */ | ||
1471 | static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; | ||
1472 | static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; | ||
1473 | #define CXT5051_SPDIF_OUT 0x1C | ||
1474 | #define CXT5051_PORTB_EVENT 0x38 | ||
1475 | #define CXT5051_PORTC_EVENT 0x39 | ||
1476 | |||
1477 | static struct hda_channel_mode cxt5051_modes[1] = { | ||
1478 | { 2, NULL }, | ||
1479 | }; | ||
1480 | |||
1481 | static void cxt5051_update_speaker(struct hda_codec *codec) | ||
1482 | { | ||
1483 | struct conexant_spec *spec = codec->spec; | ||
1484 | unsigned int pinctl; | ||
1485 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | ||
1486 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1487 | pinctl); | ||
1488 | } | ||
1489 | |||
1490 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1491 | static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1492 | struct snd_ctl_elem_value *ucontrol) | ||
1493 | { | ||
1494 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1495 | |||
1496 | if (!cxt_eapd_put(kcontrol, ucontrol)) | ||
1497 | return 0; | ||
1498 | cxt5051_update_speaker(codec); | ||
1499 | return 1; | ||
1500 | } | ||
1501 | |||
1502 | /* toggle input of built-in and mic jack appropriately */ | ||
1503 | static void cxt5051_portb_automic(struct hda_codec *codec) | ||
1504 | { | ||
1505 | unsigned int present; | ||
1506 | |||
1507 | present = snd_hda_codec_read(codec, 0x17, 0, | ||
1508 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1509 | AC_PINSENSE_PRESENCE; | ||
1510 | snd_hda_codec_write(codec, 0x14, 0, | ||
1511 | AC_VERB_SET_CONNECT_SEL, | ||
1512 | present ? 0x01 : 0x00); | ||
1513 | } | ||
1514 | |||
1515 | /* switch the current ADC according to the jack state */ | ||
1516 | static void cxt5051_portc_automic(struct hda_codec *codec) | ||
1517 | { | ||
1518 | struct conexant_spec *spec = codec->spec; | ||
1519 | unsigned int present; | ||
1520 | hda_nid_t new_adc; | ||
1521 | |||
1522 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
1523 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1524 | AC_PINSENSE_PRESENCE; | ||
1525 | if (present) | ||
1526 | spec->cur_adc_idx = 1; | ||
1527 | else | ||
1528 | spec->cur_adc_idx = 0; | ||
1529 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
1530 | if (spec->cur_adc && spec->cur_adc != new_adc) { | ||
1531 | /* stream is running, let's swap the current ADC */ | ||
1532 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
1533 | spec->cur_adc = new_adc; | ||
1534 | snd_hda_codec_setup_stream(codec, new_adc, | ||
1535 | spec->cur_adc_stream_tag, 0, | ||
1536 | spec->cur_adc_format); | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | /* mute internal speaker if HP is plugged */ | ||
1541 | static void cxt5051_hp_automute(struct hda_codec *codec) | ||
1542 | { | ||
1543 | struct conexant_spec *spec = codec->spec; | ||
1544 | |||
1545 | spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, | ||
1546 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1547 | AC_PINSENSE_PRESENCE; | ||
1548 | cxt5051_update_speaker(codec); | ||
1549 | } | ||
1550 | |||
1551 | /* unsolicited event for HP jack sensing */ | ||
1552 | static void cxt5051_hp_unsol_event(struct hda_codec *codec, | ||
1553 | unsigned int res) | ||
1554 | { | ||
1555 | switch (res >> 26) { | ||
1556 | case CONEXANT_HP_EVENT: | ||
1557 | cxt5051_hp_automute(codec); | ||
1558 | break; | ||
1559 | case CXT5051_PORTB_EVENT: | ||
1560 | cxt5051_portb_automic(codec); | ||
1561 | break; | ||
1562 | case CXT5051_PORTC_EVENT: | ||
1563 | cxt5051_portc_automic(codec); | ||
1564 | break; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | static struct snd_kcontrol_new cxt5051_mixers[] = { | ||
1569 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1570 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1571 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1572 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1573 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1574 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1575 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1576 | { | ||
1577 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1578 | .name = "Master Playback Switch", | ||
1579 | .info = cxt_eapd_info, | ||
1580 | .get = cxt_eapd_get, | ||
1581 | .put = cxt5051_hp_master_sw_put, | ||
1582 | .private_value = 0x1a, | ||
1583 | }, | ||
1584 | |||
1585 | {} | ||
1586 | }; | ||
1587 | |||
1588 | static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | ||
1589 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1590 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1591 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1592 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1593 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1594 | { | ||
1595 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1596 | .name = "Master Playback Switch", | ||
1597 | .info = cxt_eapd_info, | ||
1598 | .get = cxt_eapd_get, | ||
1599 | .put = cxt5051_hp_master_sw_put, | ||
1600 | .private_value = 0x1a, | ||
1601 | }, | ||
1602 | |||
1603 | {} | ||
1604 | }; | ||
1605 | |||
1606 | static struct hda_verb cxt5051_init_verbs[] = { | ||
1607 | /* Line in, Mic */ | ||
1608 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1609 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1610 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1611 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1612 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1613 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1614 | /* SPK */ | ||
1615 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1616 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1617 | /* HP, Amp */ | ||
1618 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1619 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1620 | /* DAC1 */ | ||
1621 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1622 | /* Record selector: Int mic */ | ||
1623 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1624 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1625 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1626 | /* SPDIF route: PCM */ | ||
1627 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1628 | /* EAPD */ | ||
1629 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1630 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1631 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1632 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1633 | { } /* end */ | ||
1634 | }; | ||
1635 | |||
1636 | /* initialize jack-sensing, too */ | ||
1637 | static int cxt5051_init(struct hda_codec *codec) | ||
1638 | { | ||
1639 | conexant_init(codec); | ||
1640 | if (codec->patch_ops.unsol_event) { | ||
1641 | cxt5051_hp_automute(codec); | ||
1642 | cxt5051_portb_automic(codec); | ||
1643 | cxt5051_portc_automic(codec); | ||
1644 | } | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | |||
1649 | enum { | ||
1650 | CXT5051_LAPTOP, /* Laptops w/ EAPD support */ | ||
1651 | CXT5051_HP, /* no docking */ | ||
1652 | CXT5051_MODELS | ||
1653 | }; | ||
1654 | |||
1655 | static const char *cxt5051_models[CXT5051_MODELS] = { | ||
1656 | [CXT5051_LAPTOP] = "laptop", | ||
1657 | [CXT5051_HP] = "hp", | ||
1658 | }; | ||
1659 | |||
1660 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | ||
1661 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||
1662 | CXT5051_LAPTOP), | ||
1663 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | ||
1664 | {} | ||
1665 | }; | ||
1666 | |||
1667 | static int patch_cxt5051(struct hda_codec *codec) | ||
1668 | { | ||
1669 | struct conexant_spec *spec; | ||
1670 | int board_config; | ||
1671 | |||
1672 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1673 | if (!spec) | ||
1674 | return -ENOMEM; | ||
1675 | mutex_init(&spec->amp_mutex); | ||
1676 | codec->spec = spec; | ||
1677 | |||
1678 | codec->patch_ops = conexant_patch_ops; | ||
1679 | codec->patch_ops.init = cxt5051_init; | ||
1680 | |||
1681 | spec->multiout.max_channels = 2; | ||
1682 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); | ||
1683 | spec->multiout.dac_nids = cxt5051_dac_nids; | ||
1684 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; | ||
1685 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ | ||
1686 | spec->adc_nids = cxt5051_adc_nids; | ||
1687 | spec->num_mixers = 1; | ||
1688 | spec->mixers[0] = cxt5051_mixers; | ||
1689 | spec->num_init_verbs = 1; | ||
1690 | spec->init_verbs[0] = cxt5051_init_verbs; | ||
1691 | spec->spdif_route = 0; | ||
1692 | spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); | ||
1693 | spec->channel_mode = cxt5051_modes; | ||
1694 | spec->cur_adc = 0; | ||
1695 | spec->cur_adc_idx = 0; | ||
1696 | |||
1697 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1698 | cxt5051_models, | ||
1699 | cxt5051_cfg_tbl); | ||
1700 | switch (board_config) { | ||
1701 | case CXT5051_HP: | ||
1702 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1703 | spec->mixers[0] = cxt5051_hp_mixers; | ||
1704 | break; | ||
1705 | default: | ||
1706 | case CXT5051_LAPTOP: | ||
1707 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1708 | break; | ||
1709 | } | ||
1710 | |||
1711 | return 0; | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | /* | ||
1716 | */ | ||
1717 | |||
1327 | struct hda_codec_preset snd_hda_preset_conexant[] = { | 1718 | struct hda_codec_preset snd_hda_preset_conexant[] = { |
1328 | { .id = 0x14f15045, .name = "CX20549 (Venice)", | 1719 | { .id = 0x14f15045, .name = "CX20549 (Venice)", |
1329 | .patch = patch_cxt5045 }, | 1720 | .patch = patch_cxt5045 }, |
1330 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", | 1721 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", |
1331 | .patch = patch_cxt5047 }, | 1722 | .patch = patch_cxt5047 }, |
1723 | { .id = 0x14f15051, .name = "CX20561 (Hermosa)", | ||
1724 | .patch = patch_cxt5051 }, | ||
1332 | {} /* terminator */ | 1725 | {} /* terminator */ |
1333 | }; | 1726 | }; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1c502789cc1e..586d98f1b63d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
@@ -92,9 +91,12 @@ enum { | |||
92 | ALC262_HP_BPC, | 91 | ALC262_HP_BPC, |
93 | ALC262_HP_BPC_D7000_WL, | 92 | ALC262_HP_BPC_D7000_WL, |
94 | ALC262_HP_BPC_D7000_WF, | 93 | ALC262_HP_BPC_D7000_WF, |
94 | ALC262_HP_TC_T5735, | ||
95 | ALC262_HP_RP5700, | ||
95 | ALC262_BENQ_ED8, | 96 | ALC262_BENQ_ED8, |
96 | ALC262_SONY_ASSAMD, | 97 | ALC262_SONY_ASSAMD, |
97 | ALC262_BENQ_T31, | 98 | ALC262_BENQ_T31, |
99 | ALC262_ULTRA, | ||
98 | ALC262_AUTO, | 100 | ALC262_AUTO, |
99 | ALC262_MODEL_LAST /* last tag */ | 101 | ALC262_MODEL_LAST /* last tag */ |
100 | }; | 102 | }; |
@@ -104,10 +106,21 @@ enum { | |||
104 | ALC268_3ST, | 106 | ALC268_3ST, |
105 | ALC268_TOSHIBA, | 107 | ALC268_TOSHIBA, |
106 | ALC268_ACER, | 108 | ALC268_ACER, |
109 | ALC268_DELL, | ||
110 | #ifdef CONFIG_SND_DEBUG | ||
111 | ALC268_TEST, | ||
112 | #endif | ||
107 | ALC268_AUTO, | 113 | ALC268_AUTO, |
108 | ALC268_MODEL_LAST /* last tag */ | 114 | ALC268_MODEL_LAST /* last tag */ |
109 | }; | 115 | }; |
110 | 116 | ||
117 | /* ALC269 models */ | ||
118 | enum { | ||
119 | ALC269_BASIC, | ||
120 | ALC269_AUTO, | ||
121 | ALC269_MODEL_LAST /* last tag */ | ||
122 | }; | ||
123 | |||
111 | /* ALC861 models */ | 124 | /* ALC861 models */ |
112 | enum { | 125 | enum { |
113 | ALC861_3ST, | 126 | ALC861_3ST, |
@@ -144,6 +157,7 @@ enum { | |||
144 | ALC662_5ST_DIG, | 157 | ALC662_5ST_DIG, |
145 | ALC662_LENOVO_101E, | 158 | ALC662_LENOVO_101E, |
146 | ALC662_ASUS_EEEPC_P701, | 159 | ALC662_ASUS_EEEPC_P701, |
160 | ALC662_ASUS_EEEPC_EP20, | ||
147 | ALC662_AUTO, | 161 | ALC662_AUTO, |
148 | ALC662_MODEL_LAST, | 162 | ALC662_MODEL_LAST, |
149 | }; | 163 | }; |
@@ -183,6 +197,8 @@ enum { | |||
183 | ALC883_HAIER_W66, | 197 | ALC883_HAIER_W66, |
184 | ALC888_6ST_HP, | 198 | ALC888_6ST_HP, |
185 | ALC888_3ST_HP, | 199 | ALC888_3ST_HP, |
200 | ALC888_6ST_DELL, | ||
201 | ALC883_MITAC, | ||
186 | ALC883_AUTO, | 202 | ALC883_AUTO, |
187 | ALC883_MODEL_LAST, | 203 | ALC883_MODEL_LAST, |
188 | }; | 204 | }; |
@@ -204,6 +220,8 @@ struct alc_spec { | |||
204 | char *stream_name_analog; /* analog PCM stream */ | 220 | char *stream_name_analog; /* analog PCM stream */ |
205 | struct hda_pcm_stream *stream_analog_playback; | 221 | struct hda_pcm_stream *stream_analog_playback; |
206 | struct hda_pcm_stream *stream_analog_capture; | 222 | struct hda_pcm_stream *stream_analog_capture; |
223 | struct hda_pcm_stream *stream_analog_alt_playback; | ||
224 | struct hda_pcm_stream *stream_analog_alt_capture; | ||
207 | 225 | ||
208 | char *stream_name_digital; /* digital PCM stream */ | 226 | char *stream_name_digital; /* digital PCM stream */ |
209 | struct hda_pcm_stream *stream_digital_playback; | 227 | struct hda_pcm_stream *stream_digital_playback; |
@@ -214,6 +232,7 @@ struct alc_spec { | |||
214 | * max_channels, dacs must be set | 232 | * max_channels, dacs must be set |
215 | * dig_out_nid and hp_nid are optional | 233 | * dig_out_nid and hp_nid are optional |
216 | */ | 234 | */ |
235 | hda_nid_t alt_dac_nid; | ||
217 | 236 | ||
218 | /* capture */ | 237 | /* capture */ |
219 | unsigned int num_adc_nids; | 238 | unsigned int num_adc_nids; |
@@ -247,7 +266,11 @@ struct alc_spec { | |||
247 | /* for pin sensing */ | 266 | /* for pin sensing */ |
248 | unsigned int sense_updated: 1; | 267 | unsigned int sense_updated: 1; |
249 | unsigned int jack_present: 1; | 268 | unsigned int jack_present: 1; |
269 | unsigned int master_sw: 1; | ||
250 | 270 | ||
271 | /* for virtual master */ | ||
272 | hda_nid_t vmaster_nid; | ||
273 | u32 vmaster_tlv[4]; | ||
251 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 274 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
252 | struct hda_loopback_check loopback; | 275 | struct hda_loopback_check loopback; |
253 | #endif | 276 | #endif |
@@ -562,7 +585,7 @@ static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, | |||
562 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | 585 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; |
563 | long *valp = ucontrol->value.integer.value; | 586 | long *valp = ucontrol->value.integer.value; |
564 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | 587 | unsigned int val = snd_hda_codec_read(codec, nid, 0, |
565 | AC_VERB_GET_DIGI_CONVERT, 0x00); | 588 | AC_VERB_GET_DIGI_CONVERT_1, 0x00); |
566 | 589 | ||
567 | *valp = (val & mask) != 0; | 590 | *valp = (val & mask) != 0; |
568 | return 0; | 591 | return 0; |
@@ -576,7 +599,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
576 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | 599 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; |
577 | long val = *ucontrol->value.integer.value; | 600 | long val = *ucontrol->value.integer.value; |
578 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, | 601 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, |
579 | AC_VERB_GET_DIGI_CONVERT, | 602 | AC_VERB_GET_DIGI_CONVERT_1, |
580 | 0x00); | 603 | 0x00); |
581 | 604 | ||
582 | /* Set/unset the masked control bit(s) as needed */ | 605 | /* Set/unset the masked control bit(s) as needed */ |
@@ -598,6 +621,59 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
598 | .private_value = nid | (mask<<16) } | 621 | .private_value = nid | (mask<<16) } |
599 | #endif /* CONFIG_SND_DEBUG */ | 622 | #endif /* CONFIG_SND_DEBUG */ |
600 | 623 | ||
624 | /* A switch control to allow the enabling EAPD digital outputs on the ALC26x. | ||
625 | * Again, this is only used in the ALC26x test models to help identify when | ||
626 | * the EAPD line must be asserted for features to work. | ||
627 | */ | ||
628 | #ifdef CONFIG_SND_DEBUG | ||
629 | #define alc_eapd_ctrl_info snd_ctl_boolean_mono_info | ||
630 | |||
631 | static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol, | ||
632 | struct snd_ctl_elem_value *ucontrol) | ||
633 | { | ||
634 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
635 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
636 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
637 | long *valp = ucontrol->value.integer.value; | ||
638 | unsigned int val = snd_hda_codec_read(codec, nid, 0, | ||
639 | AC_VERB_GET_EAPD_BTLENABLE, 0x00); | ||
640 | |||
641 | *valp = (val & mask) != 0; | ||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, | ||
646 | struct snd_ctl_elem_value *ucontrol) | ||
647 | { | ||
648 | int change; | ||
649 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
650 | hda_nid_t nid = kcontrol->private_value & 0xffff; | ||
651 | unsigned char mask = (kcontrol->private_value >> 16) & 0xff; | ||
652 | long val = *ucontrol->value.integer.value; | ||
653 | unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, | ||
654 | AC_VERB_GET_EAPD_BTLENABLE, | ||
655 | 0x00); | ||
656 | |||
657 | /* Set/unset the masked control bit(s) as needed */ | ||
658 | change = (!val ? 0 : mask) != (ctrl_data & mask); | ||
659 | if (!val) | ||
660 | ctrl_data &= ~mask; | ||
661 | else | ||
662 | ctrl_data |= mask; | ||
663 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
664 | ctrl_data); | ||
665 | |||
666 | return change; | ||
667 | } | ||
668 | |||
669 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ | ||
670 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | ||
671 | .info = alc_eapd_ctrl_info, \ | ||
672 | .get = alc_eapd_ctrl_get, \ | ||
673 | .put = alc_eapd_ctrl_put, \ | ||
674 | .private_value = nid | (mask<<16) } | ||
675 | #endif /* CONFIG_SND_DEBUG */ | ||
676 | |||
601 | /* | 677 | /* |
602 | * set up from the preset table | 678 | * set up from the preset table |
603 | */ | 679 | */ |
@@ -739,7 +815,7 @@ static void alc_subsystem_id(struct hda_codec *codec, | |||
739 | /* check sum */ | 815 | /* check sum */ |
740 | tmp = 0; | 816 | tmp = 0; |
741 | for (i = 1; i < 16; i++) { | 817 | for (i = 1; i < 16; i++) { |
742 | if ((ass >> i) && 1) | 818 | if ((ass >> i) & 1) |
743 | tmp++; | 819 | tmp++; |
744 | } | 820 | } |
745 | if (((ass >> 16) & 0xf) != tmp) | 821 | if (((ass >> 16) & 0xf) != tmp) |
@@ -828,10 +904,10 @@ do_sku: | |||
828 | break; | 904 | break; |
829 | } | 905 | } |
830 | 906 | ||
831 | /* is laptop and enable the function "Mute internal speaker | 907 | /* is laptop or Desktop and enable the function "Mute internal speaker |
832 | * when the external headphone out jack is plugged" | 908 | * when the external headphone out jack is plugged" |
833 | */ | 909 | */ |
834 | if (!(ass & 0x4) || !(ass & 0x8000)) | 910 | if (!(ass & 0x8000)) |
835 | return; | 911 | return; |
836 | /* | 912 | /* |
837 | * 10~8 : Jack location | 913 | * 10~8 : Jack location |
@@ -841,9 +917,9 @@ do_sku: | |||
841 | * when the external headphone out jack is plugged" | 917 | * when the external headphone out jack is plugged" |
842 | */ | 918 | */ |
843 | if (!spec->autocfg.speaker_pins[0]) { | 919 | if (!spec->autocfg.speaker_pins[0]) { |
844 | if (spec->multiout.dac_nids[0]) | 920 | if (spec->autocfg.line_out_pins[0]) |
845 | spec->autocfg.speaker_pins[0] = | 921 | spec->autocfg.speaker_pins[0] = |
846 | spec->multiout.dac_nids[0]; | 922 | spec->autocfg.line_out_pins[0]; |
847 | else | 923 | else |
848 | return; | 924 | return; |
849 | } | 925 | } |
@@ -1009,7 +1085,6 @@ static struct snd_kcontrol_new alc880_capture_mixer[] = { | |||
1009 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1010 | /* The multiple "Capture Source" controls confuse alsamixer | 1086 | /* The multiple "Capture Source" controls confuse alsamixer |
1011 | * So call somewhat different.. | 1087 | * So call somewhat different.. |
1012 | * FIXME: the controls appear in the "playback" view! | ||
1013 | */ | 1088 | */ |
1014 | /* .name = "Capture Source", */ | 1089 | /* .name = "Capture Source", */ |
1015 | .name = "Input Source", | 1090 | .name = "Input Source", |
@@ -1031,7 +1106,6 @@ static struct snd_kcontrol_new alc880_capture_alt_mixer[] = { | |||
1031 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1106 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1032 | /* The multiple "Capture Source" controls confuse alsamixer | 1107 | /* The multiple "Capture Source" controls confuse alsamixer |
1033 | * So call somewhat different.. | 1108 | * So call somewhat different.. |
1034 | * FIXME: the controls appear in the "playback" view! | ||
1035 | */ | 1109 | */ |
1036 | /* .name = "Capture Source", */ | 1110 | /* .name = "Capture Source", */ |
1037 | .name = "Input Source", | 1111 | .name = "Input Source", |
@@ -1226,7 +1300,6 @@ static struct snd_kcontrol_new alc880_z71v_mixer[] = { | |||
1226 | }; | 1300 | }; |
1227 | 1301 | ||
1228 | 1302 | ||
1229 | /* FIXME! */ | ||
1230 | /* | 1303 | /* |
1231 | * ALC880 F1734 model | 1304 | * ALC880 F1734 model |
1232 | * | 1305 | * |
@@ -1242,8 +1315,8 @@ static hda_nid_t alc880_f1734_dac_nids[1] = { | |||
1242 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { | 1315 | static struct snd_kcontrol_new alc880_f1734_mixer[] = { |
1243 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1316 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1244 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), | 1317 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1245 | HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1318 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1246 | HDA_BIND_MUTE("Internal Speaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1319 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1247 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 1320 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
1248 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 1321 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
1249 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1322 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
@@ -1252,7 +1325,6 @@ static struct snd_kcontrol_new alc880_f1734_mixer[] = { | |||
1252 | }; | 1325 | }; |
1253 | 1326 | ||
1254 | 1327 | ||
1255 | /* FIXME! */ | ||
1256 | /* | 1328 | /* |
1257 | * ALC880 ASUS model | 1329 | * ALC880 ASUS model |
1258 | * | 1330 | * |
@@ -1289,7 +1361,6 @@ static struct snd_kcontrol_new alc880_asus_mixer[] = { | |||
1289 | { } /* end */ | 1361 | { } /* end */ |
1290 | }; | 1362 | }; |
1291 | 1363 | ||
1292 | /* FIXME! */ | ||
1293 | /* | 1364 | /* |
1294 | * ALC880 ASUS W1V model | 1365 | * ALC880 ASUS W1V model |
1295 | * | 1366 | * |
@@ -1327,7 +1398,6 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1327 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1398 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1328 | /* The multiple "Capture Source" controls confuse alsamixer | 1399 | /* The multiple "Capture Source" controls confuse alsamixer |
1329 | * So call somewhat different.. | 1400 | * So call somewhat different.. |
1330 | * FIXME: the controls appear in the "playback" view! | ||
1331 | */ | 1401 | */ |
1332 | /* .name = "Capture Source", */ | 1402 | /* .name = "Capture Source", */ |
1333 | .name = "Input Source", | 1403 | .name = "Input Source", |
@@ -1341,10 +1411,10 @@ static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = { | |||
1341 | 1411 | ||
1342 | /* Uniwill */ | 1412 | /* Uniwill */ |
1343 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { | 1413 | static struct snd_kcontrol_new alc880_uniwill_mixer[] = { |
1344 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1414 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1345 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1415 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1346 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1416 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1347 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1417 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1348 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | 1418 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), |
1349 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 1419 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), |
1350 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | 1420 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), |
@@ -1384,16 +1454,49 @@ static struct snd_kcontrol_new alc880_fujitsu_mixer[] = { | |||
1384 | }; | 1454 | }; |
1385 | 1455 | ||
1386 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { | 1456 | static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { |
1387 | HDA_CODEC_VOLUME("HPhone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1457 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1388 | HDA_BIND_MUTE("HPhone Playback Switch", 0x0c, 2, HDA_INPUT), | 1458 | HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT), |
1389 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 1459 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
1390 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 1460 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
1391 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 1461 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
1392 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 1462 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
1393 | { } /* end */ | 1463 | { } /* end */ |
1394 | }; | 1464 | }; |
1395 | 1465 | ||
1396 | /* | 1466 | /* |
1467 | * virtual master controls | ||
1468 | */ | ||
1469 | |||
1470 | /* | ||
1471 | * slave controls for virtual master | ||
1472 | */ | ||
1473 | static const char *alc_slave_vols[] = { | ||
1474 | "Front Playback Volume", | ||
1475 | "Surround Playback Volume", | ||
1476 | "Center Playback Volume", | ||
1477 | "LFE Playback Volume", | ||
1478 | "Side Playback Volume", | ||
1479 | "Headphone Playback Volume", | ||
1480 | "Speaker Playback Volume", | ||
1481 | "Mono Playback Volume", | ||
1482 | "Line-Out Playback Volume", | ||
1483 | NULL, | ||
1484 | }; | ||
1485 | |||
1486 | static const char *alc_slave_sws[] = { | ||
1487 | "Front Playback Switch", | ||
1488 | "Surround Playback Switch", | ||
1489 | "Center Playback Switch", | ||
1490 | "LFE Playback Switch", | ||
1491 | "Side Playback Switch", | ||
1492 | "Headphone Playback Switch", | ||
1493 | "Speaker Playback Switch", | ||
1494 | "Mono Playback Switch", | ||
1495 | "IEC958 Playback Switch", | ||
1496 | NULL, | ||
1497 | }; | ||
1498 | |||
1499 | /* | ||
1397 | * build control elements | 1500 | * build control elements |
1398 | */ | 1501 | */ |
1399 | static int alc_build_controls(struct hda_codec *codec) | 1502 | static int alc_build_controls(struct hda_codec *codec) |
@@ -1419,6 +1522,23 @@ static int alc_build_controls(struct hda_codec *codec) | |||
1419 | if (err < 0) | 1522 | if (err < 0) |
1420 | return err; | 1523 | return err; |
1421 | } | 1524 | } |
1525 | |||
1526 | /* if we have no master control, let's create it */ | ||
1527 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
1528 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | ||
1529 | HDA_OUTPUT, spec->vmaster_tlv); | ||
1530 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
1531 | spec->vmaster_tlv, alc_slave_vols); | ||
1532 | if (err < 0) | ||
1533 | return err; | ||
1534 | } | ||
1535 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
1536 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
1537 | NULL, alc_slave_sws); | ||
1538 | if (err < 0) | ||
1539 | return err; | ||
1540 | } | ||
1541 | |||
1422 | return 0; | 1542 | return 0; |
1423 | } | 1543 | } |
1424 | 1544 | ||
@@ -1790,7 +1910,6 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, | |||
1790 | alc880_uniwill_p53_dcvol_automute(codec); | 1910 | alc880_uniwill_p53_dcvol_automute(codec); |
1791 | } | 1911 | } |
1792 | 1912 | ||
1793 | /* FIXME! */ | ||
1794 | /* | 1913 | /* |
1795 | * F1734 pin configuration: | 1914 | * F1734 pin configuration: |
1796 | * HP = 0x14, speaker-out = 0x15, mic = 0x18 | 1915 | * HP = 0x14, speaker-out = 0x15, mic = 0x18 |
@@ -1819,7 +1938,6 @@ static struct hda_verb alc880_pin_f1734_init_verbs[] = { | |||
1819 | { } | 1938 | { } |
1820 | }; | 1939 | }; |
1821 | 1940 | ||
1822 | /* FIXME! */ | ||
1823 | /* | 1941 | /* |
1824 | * ASUS pin configuration: | 1942 | * ASUS pin configuration: |
1825 | * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a | 1943 | * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a |
@@ -1966,9 +2084,8 @@ static struct hda_channel_mode alc880_lg_ch_modes[3] = { | |||
1966 | }; | 2084 | }; |
1967 | 2085 | ||
1968 | static struct snd_kcontrol_new alc880_lg_mixer[] = { | 2086 | static struct snd_kcontrol_new alc880_lg_mixer[] = { |
1969 | /* FIXME: it's not really "master" but front channels */ | 2087 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
1970 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 2088 | HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT), |
1971 | HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT), | ||
1972 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 2089 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1973 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), | 2090 | HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT), |
1974 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | 2091 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), |
@@ -2256,7 +2373,7 @@ static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
2256 | /* | 2373 | /* |
2257 | * Analog capture | 2374 | * Analog capture |
2258 | */ | 2375 | */ |
2259 | static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | 2376 | static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, |
2260 | struct hda_codec *codec, | 2377 | struct hda_codec *codec, |
2261 | unsigned int stream_tag, | 2378 | unsigned int stream_tag, |
2262 | unsigned int format, | 2379 | unsigned int format, |
@@ -2264,18 +2381,18 @@ static int alc880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
2264 | { | 2381 | { |
2265 | struct alc_spec *spec = codec->spec; | 2382 | struct alc_spec *spec = codec->spec; |
2266 | 2383 | ||
2267 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2384 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2268 | stream_tag, 0, format); | 2385 | stream_tag, 0, format); |
2269 | return 0; | 2386 | return 0; |
2270 | } | 2387 | } |
2271 | 2388 | ||
2272 | static int alc880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | 2389 | static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, |
2273 | struct hda_codec *codec, | 2390 | struct hda_codec *codec, |
2274 | struct snd_pcm_substream *substream) | 2391 | struct snd_pcm_substream *substream) |
2275 | { | 2392 | { |
2276 | struct alc_spec *spec = codec->spec; | 2393 | struct alc_spec *spec = codec->spec; |
2277 | 2394 | ||
2278 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 2395 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], |
2279 | 0, 0, 0); | 2396 | 0, 0, 0); |
2280 | return 0; | 2397 | return 0; |
2281 | } | 2398 | } |
@@ -2296,13 +2413,27 @@ static struct hda_pcm_stream alc880_pcm_analog_playback = { | |||
2296 | }; | 2413 | }; |
2297 | 2414 | ||
2298 | static struct hda_pcm_stream alc880_pcm_analog_capture = { | 2415 | static struct hda_pcm_stream alc880_pcm_analog_capture = { |
2299 | .substreams = 2, | 2416 | .substreams = 1, |
2417 | .channels_min = 2, | ||
2418 | .channels_max = 2, | ||
2419 | /* NID is set in alc_build_pcms */ | ||
2420 | }; | ||
2421 | |||
2422 | static struct hda_pcm_stream alc880_pcm_analog_alt_playback = { | ||
2423 | .substreams = 1, | ||
2424 | .channels_min = 2, | ||
2425 | .channels_max = 2, | ||
2426 | /* NID is set in alc_build_pcms */ | ||
2427 | }; | ||
2428 | |||
2429 | static struct hda_pcm_stream alc880_pcm_analog_alt_capture = { | ||
2430 | .substreams = 2, /* can be overridden */ | ||
2300 | .channels_min = 2, | 2431 | .channels_min = 2, |
2301 | .channels_max = 2, | 2432 | .channels_max = 2, |
2302 | /* NID is set in alc_build_pcms */ | 2433 | /* NID is set in alc_build_pcms */ |
2303 | .ops = { | 2434 | .ops = { |
2304 | .prepare = alc880_capture_pcm_prepare, | 2435 | .prepare = alc880_alt_capture_pcm_prepare, |
2305 | .cleanup = alc880_capture_pcm_cleanup | 2436 | .cleanup = alc880_alt_capture_pcm_cleanup |
2306 | }, | 2437 | }, |
2307 | }; | 2438 | }; |
2308 | 2439 | ||
@@ -2326,7 +2457,7 @@ static struct hda_pcm_stream alc880_pcm_digital_capture = { | |||
2326 | }; | 2457 | }; |
2327 | 2458 | ||
2328 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ | 2459 | /* Used by alc_build_pcms to flag that a PCM has no playback stream */ |
2329 | static struct hda_pcm_stream alc_pcm_null_playback = { | 2460 | static struct hda_pcm_stream alc_pcm_null_stream = { |
2330 | .substreams = 0, | 2461 | .substreams = 0, |
2331 | .channels_min = 0, | 2462 | .channels_min = 0, |
2332 | .channels_max = 0, | 2463 | .channels_max = 0, |
@@ -2383,17 +2514,32 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
2383 | * model, configure a second analog capture-only PCM. | 2514 | * model, configure a second analog capture-only PCM. |
2384 | */ | 2515 | */ |
2385 | /* Additional Analaog capture for index #2 */ | 2516 | /* Additional Analaog capture for index #2 */ |
2386 | if (spec->num_adc_nids > 1 && spec->stream_analog_capture && | 2517 | if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) || |
2387 | spec->adc_nids) { | 2518 | (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) { |
2388 | codec->num_pcms = 3; | 2519 | codec->num_pcms = 3; |
2389 | info = spec->pcm_rec + 2; | 2520 | info = spec->pcm_rec + 2; |
2390 | info->name = spec->stream_name_analog; | 2521 | info->name = spec->stream_name_analog; |
2391 | /* No playback stream for second PCM */ | 2522 | if (spec->alt_dac_nid) { |
2392 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback; | 2523 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = |
2393 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | 2524 | *spec->stream_analog_alt_playback; |
2394 | if (spec->stream_analog_capture) { | 2525 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
2395 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); | 2526 | spec->alt_dac_nid; |
2396 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1]; | 2527 | } else { |
2528 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
2529 | alc_pcm_null_stream; | ||
2530 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; | ||
2531 | } | ||
2532 | if (spec->num_adc_nids > 1) { | ||
2533 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2534 | *spec->stream_analog_alt_capture; | ||
2535 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | ||
2536 | spec->adc_nids[1]; | ||
2537 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = | ||
2538 | spec->num_adc_nids - 1; | ||
2539 | } else { | ||
2540 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
2541 | alc_pcm_null_stream; | ||
2542 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; | ||
2397 | } | 2543 | } |
2398 | } | 2544 | } |
2399 | 2545 | ||
@@ -2723,23 +2869,17 @@ static const char *alc880_models[ALC880_MODEL_LAST] = { | |||
2723 | }; | 2869 | }; |
2724 | 2870 | ||
2725 | static struct snd_pci_quirk alc880_cfg_tbl[] = { | 2871 | static struct snd_pci_quirk alc880_cfg_tbl[] = { |
2726 | /* Broken BIOS configuration */ | 2872 | SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), |
2727 | SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), | ||
2728 | SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), | ||
2729 | |||
2730 | SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), | 2873 | SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG), |
2731 | SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), | 2874 | SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST), |
2732 | SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810), | ||
2733 | SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), | 2875 | SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG), |
2734 | SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), | 2876 | SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG), |
2735 | SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), | 2877 | SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG), |
2736 | SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), | 2878 | SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG), |
2737 | SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), | 2879 | SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG), |
2738 | SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), | 2880 | SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST), |
2739 | |||
2740 | SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), | 2881 | SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG), |
2741 | SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), | 2882 | SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST), |
2742 | |||
2743 | SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), | 2883 | SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V), |
2744 | SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), | 2884 | SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG), |
2745 | SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), | 2885 | SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG), |
@@ -2754,54 +2894,50 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { | |||
2754 | SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), | 2894 | SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG), |
2755 | SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), | 2895 | SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST), |
2756 | SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), | 2896 | SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST), |
2757 | SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), | 2897 | SND_PCI_QUIRK(0x1043, 0, "ASUS", ALC880_ASUS), /* default ASUS */ |
2758 | |||
2759 | SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), | ||
2760 | SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), | 2898 | SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST), |
2899 | SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST), | ||
2900 | SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), | ||
2761 | SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), | 2901 | SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST), |
2762 | SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), | 2902 | SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST), |
2763 | SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST), | ||
2764 | SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), | ||
2765 | SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), | ||
2766 | SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), | ||
2767 | SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), | ||
2768 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | ||
2769 | SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), | ||
2770 | SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), | ||
2771 | SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), | ||
2772 | SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), | 2903 | SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG), |
2773 | SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), | 2904 | SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG), |
2774 | SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), | 2905 | SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG), |
2775 | SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), | 2906 | SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG), |
2907 | SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO), | ||
2908 | SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO), | ||
2776 | SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), | 2909 | SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2), |
2777 | 2910 | SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG), | |
2778 | SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), | 2911 | SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG), |
2912 | SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), | ||
2779 | SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), | 2913 | SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL), |
2780 | SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), | 2914 | SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53), |
2781 | SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734), | 2915 | SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810), |
2782 | 2916 | SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG), | |
2783 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), | 2917 | SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), |
2784 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | ||
2785 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), | 2918 | SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), |
2919 | SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), | ||
2786 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), | 2920 | SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), |
2787 | 2921 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | |
2788 | SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), | 2922 | SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), |
2789 | SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), | 2923 | SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG), |
2790 | SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), | ||
2791 | SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), | 2924 | SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW), |
2792 | 2925 | SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700), | |
2793 | SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), | 2926 | SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */ |
2794 | SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), | 2927 | SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG), |
2795 | SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), | 2928 | SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), |
2796 | SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), | 2929 | SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG), |
2797 | SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), | 2930 | SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG), |
2931 | SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG), | ||
2798 | SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), | 2932 | SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG), |
2933 | SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG), | ||
2934 | SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG), | ||
2799 | SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), | 2935 | SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG), |
2800 | SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), | 2936 | SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG), |
2801 | SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), | 2937 | SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG), |
2802 | SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG), | 2938 | SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), /* default Intel */ |
2803 | SND_PCI_QUIRK(0x8086, 0, "Intel mobo", ALC880_3ST), | 2939 | SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG), |
2804 | 2940 | SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG), | |
2805 | {} | 2941 | {} |
2806 | }; | 2942 | }; |
2807 | 2943 | ||
@@ -3511,6 +3647,7 @@ static int patch_alc880(struct hda_codec *codec) | |||
3511 | spec->stream_name_analog = "ALC880 Analog"; | 3647 | spec->stream_name_analog = "ALC880 Analog"; |
3512 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 3648 | spec->stream_analog_playback = &alc880_pcm_analog_playback; |
3513 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | 3649 | spec->stream_analog_capture = &alc880_pcm_analog_capture; |
3650 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
3514 | 3651 | ||
3515 | spec->stream_name_digital = "ALC880 Digital"; | 3652 | spec->stream_name_digital = "ALC880 Digital"; |
3516 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 3653 | spec->stream_digital_playback = &alc880_pcm_digital_playback; |
@@ -3535,6 +3672,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
3535 | } | 3672 | } |
3536 | } | 3673 | } |
3537 | 3674 | ||
3675 | spec->vmaster_nid = 0x0c; | ||
3676 | |||
3538 | codec->patch_ops = alc_patch_ops; | 3677 | codec->patch_ops = alc_patch_ops; |
3539 | if (board_config == ALC880_AUTO) | 3678 | if (board_config == ALC880_AUTO) |
3540 | spec->init_hook = alc880_auto_init; | 3679 | spec->init_hook = alc880_auto_init; |
@@ -3691,18 +3830,135 @@ static struct snd_kcontrol_new alc260_pc_beep_mixer[] = { | |||
3691 | { } /* end */ | 3830 | { } /* end */ |
3692 | }; | 3831 | }; |
3693 | 3832 | ||
3833 | /* update HP, line and mono out pins according to the master switch */ | ||
3834 | static void alc260_hp_master_update(struct hda_codec *codec, | ||
3835 | hda_nid_t hp, hda_nid_t line, | ||
3836 | hda_nid_t mono) | ||
3837 | { | ||
3838 | struct alc_spec *spec = codec->spec; | ||
3839 | unsigned int val = spec->master_sw ? PIN_HP : 0; | ||
3840 | /* change HP and line-out pins */ | ||
3841 | snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3842 | val); | ||
3843 | snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3844 | val); | ||
3845 | /* mono (speaker) depending on the HP jack sense */ | ||
3846 | val = (val && !spec->jack_present) ? PIN_OUT : 0; | ||
3847 | snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3848 | val); | ||
3849 | } | ||
3850 | |||
3851 | static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol, | ||
3852 | struct snd_ctl_elem_value *ucontrol) | ||
3853 | { | ||
3854 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3855 | struct alc_spec *spec = codec->spec; | ||
3856 | *ucontrol->value.integer.value = spec->master_sw; | ||
3857 | return 0; | ||
3858 | } | ||
3859 | |||
3860 | static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
3861 | struct snd_ctl_elem_value *ucontrol) | ||
3862 | { | ||
3863 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3864 | struct alc_spec *spec = codec->spec; | ||
3865 | int val = !!*ucontrol->value.integer.value; | ||
3866 | hda_nid_t hp, line, mono; | ||
3867 | |||
3868 | if (val == spec->master_sw) | ||
3869 | return 0; | ||
3870 | spec->master_sw = val; | ||
3871 | hp = (kcontrol->private_value >> 16) & 0xff; | ||
3872 | line = (kcontrol->private_value >> 8) & 0xff; | ||
3873 | mono = kcontrol->private_value & 0xff; | ||
3874 | alc260_hp_master_update(codec, hp, line, mono); | ||
3875 | return 1; | ||
3876 | } | ||
3877 | |||
3878 | static struct snd_kcontrol_new alc260_hp_output_mixer[] = { | ||
3879 | { | ||
3880 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3881 | .name = "Master Playback Switch", | ||
3882 | .info = snd_ctl_boolean_mono_info, | ||
3883 | .get = alc260_hp_master_sw_get, | ||
3884 | .put = alc260_hp_master_sw_put, | ||
3885 | .private_value = (0x0f << 16) | (0x10 << 8) | 0x11 | ||
3886 | }, | ||
3887 | HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT), | ||
3888 | HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT), | ||
3889 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT), | ||
3890 | HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT), | ||
3891 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, | ||
3892 | HDA_OUTPUT), | ||
3893 | HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT), | ||
3894 | { } /* end */ | ||
3895 | }; | ||
3896 | |||
3897 | static struct hda_verb alc260_hp_unsol_verbs[] = { | ||
3898 | {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
3899 | {}, | ||
3900 | }; | ||
3901 | |||
3902 | static void alc260_hp_automute(struct hda_codec *codec) | ||
3903 | { | ||
3904 | struct alc_spec *spec = codec->spec; | ||
3905 | unsigned int present; | ||
3906 | |||
3907 | present = snd_hda_codec_read(codec, 0x10, 0, | ||
3908 | AC_VERB_GET_PIN_SENSE, 0); | ||
3909 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
3910 | alc260_hp_master_update(codec, 0x0f, 0x10, 0x11); | ||
3911 | } | ||
3912 | |||
3913 | static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res) | ||
3914 | { | ||
3915 | if ((res >> 26) == ALC880_HP_EVENT) | ||
3916 | alc260_hp_automute(codec); | ||
3917 | } | ||
3918 | |||
3694 | static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { | 3919 | static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { |
3920 | { | ||
3921 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3922 | .name = "Master Playback Switch", | ||
3923 | .info = snd_ctl_boolean_mono_info, | ||
3924 | .get = alc260_hp_master_sw_get, | ||
3925 | .put = alc260_hp_master_sw_put, | ||
3926 | .private_value = (0x10 << 16) | (0x15 << 8) | 0x11 | ||
3927 | }, | ||
3695 | HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), | 3928 | HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT), |
3696 | HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), | 3929 | HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT), |
3697 | HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), | 3930 | HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT), |
3698 | HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), | 3931 | HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT), |
3699 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), | 3932 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT), |
3700 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 3933 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
3701 | HDA_CODEC_VOLUME_MONO("iSpeaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), | 3934 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), |
3702 | HDA_CODEC_MUTE_MONO("iSpeaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), | 3935 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT), |
3703 | { } /* end */ | 3936 | { } /* end */ |
3704 | }; | 3937 | }; |
3705 | 3938 | ||
3939 | static struct hda_verb alc260_hp_3013_unsol_verbs[] = { | ||
3940 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
3941 | {}, | ||
3942 | }; | ||
3943 | |||
3944 | static void alc260_hp_3013_automute(struct hda_codec *codec) | ||
3945 | { | ||
3946 | struct alc_spec *spec = codec->spec; | ||
3947 | unsigned int present; | ||
3948 | |||
3949 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
3950 | AC_VERB_GET_PIN_SENSE, 0); | ||
3951 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
3952 | alc260_hp_master_update(codec, 0x10, 0x15, 0x11); | ||
3953 | } | ||
3954 | |||
3955 | static void alc260_hp_3013_unsol_event(struct hda_codec *codec, | ||
3956 | unsigned int res) | ||
3957 | { | ||
3958 | if ((res >> 26) == ALC880_HP_EVENT) | ||
3959 | alc260_hp_3013_automute(codec); | ||
3960 | } | ||
3961 | |||
3706 | /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, | 3962 | /* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12, |
3707 | * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. | 3963 | * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10. |
3708 | */ | 3964 | */ |
@@ -3812,7 +4068,6 @@ static struct snd_kcontrol_new alc260_capture_mixer[] = { | |||
3812 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4068 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3813 | /* The multiple "Capture Source" controls confuse alsamixer | 4069 | /* The multiple "Capture Source" controls confuse alsamixer |
3814 | * So call somewhat different.. | 4070 | * So call somewhat different.. |
3815 | * FIXME: the controls appear in the "playback" view! | ||
3816 | */ | 4071 | */ |
3817 | /* .name = "Capture Source", */ | 4072 | /* .name = "Capture Source", */ |
3818 | .name = "Input Source", | 4073 | .name = "Input Source", |
@@ -3831,7 +4086,6 @@ static struct snd_kcontrol_new alc260_capture_alt_mixer[] = { | |||
3831 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4086 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
3832 | /* The multiple "Capture Source" controls confuse alsamixer | 4087 | /* The multiple "Capture Source" controls confuse alsamixer |
3833 | * So call somewhat different.. | 4088 | * So call somewhat different.. |
3834 | * FIXME: the controls appear in the "playback" view! | ||
3835 | */ | 4089 | */ |
3836 | /* .name = "Capture Source", */ | 4090 | /* .name = "Capture Source", */ |
3837 | .name = "Input Source", | 4091 | .name = "Input Source", |
@@ -4332,6 +4586,12 @@ static struct snd_kcontrol_new alc260_test_mixer[] = { | |||
4332 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), | 4586 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01), |
4333 | ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), | 4587 | ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01), |
4334 | 4588 | ||
4589 | /* A switch allowing EAPD to be enabled. Some laptops seem to use | ||
4590 | * this output to turn on an external amplifier. | ||
4591 | */ | ||
4592 | ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), | ||
4593 | ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), | ||
4594 | |||
4335 | { } /* end */ | 4595 | { } /* end */ |
4336 | }; | 4596 | }; |
4337 | static struct hda_verb alc260_test_init_verbs[] = { | 4597 | static struct hda_verb alc260_test_init_verbs[] = { |
@@ -4417,17 +4677,8 @@ static struct hda_verb alc260_test_init_verbs[] = { | |||
4417 | }; | 4677 | }; |
4418 | #endif | 4678 | #endif |
4419 | 4679 | ||
4420 | static struct hda_pcm_stream alc260_pcm_analog_playback = { | 4680 | #define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback |
4421 | .substreams = 1, | 4681 | #define alc260_pcm_analog_capture alc880_pcm_analog_capture |
4422 | .channels_min = 2, | ||
4423 | .channels_max = 2, | ||
4424 | }; | ||
4425 | |||
4426 | static struct hda_pcm_stream alc260_pcm_analog_capture = { | ||
4427 | .substreams = 1, | ||
4428 | .channels_min = 2, | ||
4429 | .channels_max = 2, | ||
4430 | }; | ||
4431 | 4682 | ||
4432 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback | 4683 | #define alc260_pcm_digital_playback alc880_pcm_digital_playback |
4433 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture | 4684 | #define alc260_pcm_digital_capture alc880_pcm_digital_capture |
@@ -4744,8 +4995,8 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { | |||
4744 | SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), | 4995 | SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC), |
4745 | SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), | 4996 | SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X), |
4746 | SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), | 4997 | SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC), |
4747 | SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), | ||
4748 | SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), | 4998 | SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V), |
4999 | SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL), | ||
4749 | {} | 5000 | {} |
4750 | }; | 5001 | }; |
4751 | 5002 | ||
@@ -4765,10 +5016,11 @@ static struct alc_config_preset alc260_presets[] = { | |||
4765 | .input_mux = &alc260_capture_source, | 5016 | .input_mux = &alc260_capture_source, |
4766 | }, | 5017 | }, |
4767 | [ALC260_HP] = { | 5018 | [ALC260_HP] = { |
4768 | .mixers = { alc260_base_output_mixer, | 5019 | .mixers = { alc260_hp_output_mixer, |
4769 | alc260_input_mixer, | 5020 | alc260_input_mixer, |
4770 | alc260_capture_alt_mixer }, | 5021 | alc260_capture_alt_mixer }, |
4771 | .init_verbs = { alc260_init_verbs }, | 5022 | .init_verbs = { alc260_init_verbs, |
5023 | alc260_hp_unsol_verbs }, | ||
4772 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | 5024 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), |
4773 | .dac_nids = alc260_dac_nids, | 5025 | .dac_nids = alc260_dac_nids, |
4774 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | 5026 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), |
@@ -4776,12 +5028,15 @@ static struct alc_config_preset alc260_presets[] = { | |||
4776 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | 5028 | .num_channel_mode = ARRAY_SIZE(alc260_modes), |
4777 | .channel_mode = alc260_modes, | 5029 | .channel_mode = alc260_modes, |
4778 | .input_mux = &alc260_capture_source, | 5030 | .input_mux = &alc260_capture_source, |
5031 | .unsol_event = alc260_hp_unsol_event, | ||
5032 | .init_hook = alc260_hp_automute, | ||
4779 | }, | 5033 | }, |
4780 | [ALC260_HP_3013] = { | 5034 | [ALC260_HP_3013] = { |
4781 | .mixers = { alc260_hp_3013_mixer, | 5035 | .mixers = { alc260_hp_3013_mixer, |
4782 | alc260_input_mixer, | 5036 | alc260_input_mixer, |
4783 | alc260_capture_alt_mixer }, | 5037 | alc260_capture_alt_mixer }, |
4784 | .init_verbs = { alc260_hp_3013_init_verbs }, | 5038 | .init_verbs = { alc260_hp_3013_init_verbs, |
5039 | alc260_hp_3013_unsol_verbs }, | ||
4785 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | 5040 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), |
4786 | .dac_nids = alc260_dac_nids, | 5041 | .dac_nids = alc260_dac_nids, |
4787 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | 5042 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), |
@@ -4789,6 +5044,8 @@ static struct alc_config_preset alc260_presets[] = { | |||
4789 | .num_channel_mode = ARRAY_SIZE(alc260_modes), | 5044 | .num_channel_mode = ARRAY_SIZE(alc260_modes), |
4790 | .channel_mode = alc260_modes, | 5045 | .channel_mode = alc260_modes, |
4791 | .input_mux = &alc260_capture_source, | 5046 | .input_mux = &alc260_capture_source, |
5047 | .unsol_event = alc260_hp_3013_unsol_event, | ||
5048 | .init_hook = alc260_hp_3013_automute, | ||
4792 | }, | 5049 | }, |
4793 | [ALC260_FUJITSU_S702X] = { | 5050 | [ALC260_FUJITSU_S702X] = { |
4794 | .mixers = { alc260_fujitsu_mixer, | 5051 | .mixers = { alc260_fujitsu_mixer, |
@@ -4906,6 +5163,8 @@ static int patch_alc260(struct hda_codec *codec) | |||
4906 | spec->stream_digital_playback = &alc260_pcm_digital_playback; | 5163 | spec->stream_digital_playback = &alc260_pcm_digital_playback; |
4907 | spec->stream_digital_capture = &alc260_pcm_digital_capture; | 5164 | spec->stream_digital_capture = &alc260_pcm_digital_capture; |
4908 | 5165 | ||
5166 | spec->vmaster_nid = 0x08; | ||
5167 | |||
4909 | codec->patch_ops = alc_patch_ops; | 5168 | codec->patch_ops = alc_patch_ops; |
4910 | if (board_config == ALC260_AUTO) | 5169 | if (board_config == ALC260_AUTO) |
4911 | spec->init_hook = alc260_auto_init; | 5170 | spec->init_hook = alc260_auto_init; |
@@ -5106,15 +5365,15 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
5106 | }; | 5365 | }; |
5107 | 5366 | ||
5108 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | 5367 | static struct snd_kcontrol_new alc885_mbp3_mixer[] = { |
5109 | HDA_CODEC_VOLUME("Master Volume", 0x0c, 0x00, HDA_OUTPUT), | 5368 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), |
5110 | HDA_BIND_MUTE ("Master Switch", 0x0c, 0x02, HDA_INPUT), | 5369 | HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), |
5111 | HDA_CODEC_MUTE ("Speaker Switch", 0x14, 0x00, HDA_OUTPUT), | 5370 | HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT), |
5112 | HDA_CODEC_VOLUME("Line Out Volume", 0x0d,0x00, HDA_OUTPUT), | 5371 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0d, 0x00, HDA_OUTPUT), |
5113 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x0b, 0x02, HDA_INPUT), | 5372 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
5114 | HDA_CODEC_MUTE ("Line In Playback Switch", 0x0b, 0x02, HDA_INPUT), | 5373 | HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
5115 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), | 5374 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), |
5116 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), | 5375 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), |
5117 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0x00, HDA_INPUT), | 5376 | HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), |
5118 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | 5377 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), |
5119 | { } /* end */ | 5378 | { } /* end */ |
5120 | }; | 5379 | }; |
@@ -5679,7 +5938,6 @@ static struct snd_kcontrol_new alc882_capture_alt_mixer[] = { | |||
5679 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5938 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5680 | /* The multiple "Capture Source" controls confuse alsamixer | 5939 | /* The multiple "Capture Source" controls confuse alsamixer |
5681 | * So call somewhat different.. | 5940 | * So call somewhat different.. |
5682 | * FIXME: the controls appear in the "playback" view! | ||
5683 | */ | 5941 | */ |
5684 | /* .name = "Capture Source", */ | 5942 | /* .name = "Capture Source", */ |
5685 | .name = "Input Source", | 5943 | .name = "Input Source", |
@@ -5702,7 +5960,6 @@ static struct snd_kcontrol_new alc882_capture_mixer[] = { | |||
5702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5960 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
5703 | /* The multiple "Capture Source" controls confuse alsamixer | 5961 | /* The multiple "Capture Source" controls confuse alsamixer |
5704 | * So call somewhat different.. | 5962 | * So call somewhat different.. |
5705 | * FIXME: the controls appear in the "playback" view! | ||
5706 | */ | 5963 | */ |
5707 | /* .name = "Capture Source", */ | 5964 | /* .name = "Capture Source", */ |
5708 | .name = "Input Source", | 5965 | .name = "Input Source", |
@@ -5743,16 +6000,17 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { | |||
5743 | 6000 | ||
5744 | static struct snd_pci_quirk alc882_cfg_tbl[] = { | 6001 | static struct snd_pci_quirk alc882_cfg_tbl[] = { |
5745 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), | 6002 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), |
5746 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), | ||
5747 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | ||
5748 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | ||
5749 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), | ||
5750 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), | 6003 | SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), |
5751 | SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), | 6004 | SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), |
5752 | SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), | 6005 | SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), |
6006 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), | ||
5753 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), | 6007 | SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), |
5754 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), | 6008 | SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), |
5755 | SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), | 6009 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), |
6010 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), | ||
6011 | SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ | ||
6012 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), | ||
6013 | SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), | ||
5756 | {} | 6014 | {} |
5757 | }; | 6015 | }; |
5758 | 6016 | ||
@@ -5990,7 +6248,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
5990 | hda_nid_t nid; | 6248 | hda_nid_t nid; |
5991 | 6249 | ||
5992 | nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; | 6250 | nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; |
5993 | if (nid) { | 6251 | if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { |
5994 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 6252 | err = add_control(spec, ALC_CTL_WIDGET_VOL, |
5995 | "Mic Boost", | 6253 | "Mic Boost", |
5996 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 6254 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
@@ -5998,7 +6256,7 @@ static int alc_auto_add_mic_boost(struct hda_codec *codec) | |||
5998 | return err; | 6256 | return err; |
5999 | } | 6257 | } |
6000 | nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; | 6258 | nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; |
6001 | if (nid) { | 6259 | if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { |
6002 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | 6260 | err = add_control(spec, ALC_CTL_WIDGET_VOL, |
6003 | "Front Mic Boost", | 6261 | "Front Mic Boost", |
6004 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); | 6262 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); |
@@ -6061,6 +6319,7 @@ static int patch_alc882(struct hda_codec *codec) | |||
6061 | case 0x106b1000: /* iMac 24 */ | 6319 | case 0x106b1000: /* iMac 24 */ |
6062 | board_config = ALC885_IMAC24; | 6320 | board_config = ALC885_IMAC24; |
6063 | break; | 6321 | break; |
6322 | case 0x106b00a1: /* Macbook */ | ||
6064 | case 0x106b2c00: /* Macbook Pro rev3 */ | 6323 | case 0x106b2c00: /* Macbook Pro rev3 */ |
6065 | board_config = ALC885_MBP3; | 6324 | board_config = ALC885_MBP3; |
6066 | break; | 6325 | break; |
@@ -6093,6 +6352,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
6093 | spec->stream_name_analog = "ALC882 Analog"; | 6352 | spec->stream_name_analog = "ALC882 Analog"; |
6094 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 6353 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
6095 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 6354 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
6355 | /* FIXME: setup DAC5 */ | ||
6356 | /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ | ||
6357 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | ||
6096 | 6358 | ||
6097 | spec->stream_name_digital = "ALC882 Digital"; | 6359 | spec->stream_name_digital = "ALC882 Digital"; |
6098 | spec->stream_digital_playback = &alc882_pcm_digital_playback; | 6360 | spec->stream_digital_playback = &alc882_pcm_digital_playback; |
@@ -6117,6 +6379,8 @@ static int patch_alc882(struct hda_codec *codec) | |||
6117 | } | 6379 | } |
6118 | } | 6380 | } |
6119 | 6381 | ||
6382 | spec->vmaster_nid = 0x0c; | ||
6383 | |||
6120 | codec->patch_ops = alc_patch_ops; | 6384 | codec->patch_ops = alc_patch_ops; |
6121 | if (board_config == ALC882_AUTO) | 6385 | if (board_config == ALC882_AUTO) |
6122 | spec->init_hook = alc882_auto_init; | 6386 | spec->init_hook = alc882_auto_init; |
@@ -6340,6 +6604,36 @@ static struct snd_kcontrol_new alc883_base_mixer[] = { | |||
6340 | { } /* end */ | 6604 | { } /* end */ |
6341 | }; | 6605 | }; |
6342 | 6606 | ||
6607 | static struct snd_kcontrol_new alc883_mitac_mixer[] = { | ||
6608 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
6609 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
6610 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), | ||
6611 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | ||
6612 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
6613 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), | ||
6614 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
6615 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
6616 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
6617 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
6618 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
6619 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
6620 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
6621 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6622 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6623 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
6624 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
6625 | { | ||
6626 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6627 | /* .name = "Capture Source", */ | ||
6628 | .name = "Input Source", | ||
6629 | .count = 2, | ||
6630 | .info = alc883_mux_enum_info, | ||
6631 | .get = alc883_mux_enum_get, | ||
6632 | .put = alc883_mux_enum_put, | ||
6633 | }, | ||
6634 | { } /* end */ | ||
6635 | }; | ||
6636 | |||
6343 | static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { | 6637 | static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = { |
6344 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6638 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6345 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6639 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -6508,8 +6802,8 @@ static struct snd_kcontrol_new alc883_tagra_2ch_mixer[] = { | |||
6508 | static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { | 6802 | static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = { |
6509 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6803 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6510 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6804 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
6511 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 6805 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
6512 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x0d, 2, HDA_INPUT), | 6806 | HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT), |
6513 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 6807 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
6514 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 6808 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
6515 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 6809 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -6658,6 +6952,46 @@ static struct snd_kcontrol_new alc888_3st_hp_mixer[] = { | |||
6658 | { } /* end */ | 6952 | { } /* end */ |
6659 | }; | 6953 | }; |
6660 | 6954 | ||
6955 | static struct snd_kcontrol_new alc888_6st_dell_mixer[] = { | ||
6956 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
6957 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
6958 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
6959 | HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT), | ||
6960 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT), | ||
6961 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT), | ||
6962 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT), | ||
6963 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), | ||
6964 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | ||
6965 | HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), | ||
6966 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
6967 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
6968 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
6969 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
6970 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
6971 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
6972 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
6973 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
6974 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
6975 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
6976 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
6977 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | ||
6978 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | ||
6979 | HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT), | ||
6980 | HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT), | ||
6981 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT), | ||
6982 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT), | ||
6983 | { | ||
6984 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
6985 | /* .name = "Capture Source", */ | ||
6986 | .name = "Input Source", | ||
6987 | .count = 2, | ||
6988 | .info = alc883_mux_enum_info, | ||
6989 | .get = alc883_mux_enum_get, | ||
6990 | .put = alc883_mux_enum_put, | ||
6991 | }, | ||
6992 | { } /* end */ | ||
6993 | }; | ||
6994 | |||
6661 | static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { | 6995 | static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = { |
6662 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6996 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6663 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6997 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -6772,6 +7106,67 @@ static struct hda_verb alc883_init_verbs[] = { | |||
6772 | { } | 7106 | { } |
6773 | }; | 7107 | }; |
6774 | 7108 | ||
7109 | /* toggle speaker-output according to the hp-jack state */ | ||
7110 | static void alc883_mitac_hp_automute(struct hda_codec *codec) | ||
7111 | { | ||
7112 | unsigned int present; | ||
7113 | |||
7114 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
7115 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7116 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
7117 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7118 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
7119 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7120 | } | ||
7121 | |||
7122 | /* auto-toggle front mic */ | ||
7123 | /* | ||
7124 | static void alc883_mitac_mic_automute(struct hda_codec *codec) | ||
7125 | { | ||
7126 | unsigned int present; | ||
7127 | unsigned char bits; | ||
7128 | |||
7129 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
7130 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7131 | bits = present ? HDA_AMP_MUTE : 0; | ||
7132 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); | ||
7133 | } | ||
7134 | */ | ||
7135 | |||
7136 | static void alc883_mitac_automute(struct hda_codec *codec) | ||
7137 | { | ||
7138 | alc883_mitac_hp_automute(codec); | ||
7139 | /* alc883_mitac_mic_automute(codec); */ | ||
7140 | } | ||
7141 | |||
7142 | static void alc883_mitac_unsol_event(struct hda_codec *codec, | ||
7143 | unsigned int res) | ||
7144 | { | ||
7145 | switch (res >> 26) { | ||
7146 | case ALC880_HP_EVENT: | ||
7147 | alc883_mitac_hp_automute(codec); | ||
7148 | break; | ||
7149 | case ALC880_MIC_EVENT: | ||
7150 | /* alc883_mitac_mic_automute(codec); */ | ||
7151 | break; | ||
7152 | } | ||
7153 | } | ||
7154 | |||
7155 | static struct hda_verb alc883_mitac_verbs[] = { | ||
7156 | /* HP */ | ||
7157 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
7158 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
7159 | /* Subwoofer */ | ||
7160 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
7161 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
7162 | |||
7163 | /* enable unsolicited event */ | ||
7164 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7165 | /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */ | ||
7166 | |||
7167 | { } /* end */ | ||
7168 | }; | ||
7169 | |||
6775 | static struct hda_verb alc883_tagra_verbs[] = { | 7170 | static struct hda_verb alc883_tagra_verbs[] = { |
6776 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 7171 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
6777 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7172 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
@@ -6843,6 +7238,15 @@ static struct hda_verb alc888_3st_hp_verbs[] = { | |||
6843 | { } | 7238 | { } |
6844 | }; | 7239 | }; |
6845 | 7240 | ||
7241 | static struct hda_verb alc888_6st_dell_verbs[] = { | ||
7242 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */ | ||
7243 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 1 (0x0e) */ | ||
7244 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 2 (0x0d) */ | ||
7245 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */ | ||
7246 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
7247 | { } | ||
7248 | }; | ||
7249 | |||
6846 | static struct hda_verb alc888_3st_hp_2ch_init[] = { | 7250 | static struct hda_verb alc888_3st_hp_2ch_init[] = { |
6847 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | 7251 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, |
6848 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | 7252 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, |
@@ -7038,6 +7442,33 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { | |||
7038 | { } | 7442 | { } |
7039 | }; | 7443 | }; |
7040 | 7444 | ||
7445 | static void alc888_6st_dell_front_automute(struct hda_codec *codec) | ||
7446 | { | ||
7447 | unsigned int present; | ||
7448 | |||
7449 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
7450 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
7451 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
7452 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7453 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
7454 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7455 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
7456 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7457 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
7458 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7459 | } | ||
7460 | |||
7461 | static void alc888_6st_dell_unsol_event(struct hda_codec *codec, | ||
7462 | unsigned int res) | ||
7463 | { | ||
7464 | switch (res >> 26) { | ||
7465 | case ALC880_HP_EVENT: | ||
7466 | printk("hp_event\n"); | ||
7467 | alc888_6st_dell_front_automute(codec); | ||
7468 | break; | ||
7469 | } | ||
7470 | } | ||
7471 | |||
7041 | /* | 7472 | /* |
7042 | * generic initialization of ADC, input mixers and output mixers | 7473 | * generic initialization of ADC, input mixers and output mixers |
7043 | */ | 7474 | */ |
@@ -7096,7 +7527,7 @@ static struct hda_verb alc883_auto_init_verbs[] = { | |||
7096 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 7527 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
7097 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | 7528 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
7098 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ | 7529 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ |
7099 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | 7530 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
7100 | 7531 | ||
7101 | { } | 7532 | { } |
7102 | }; | 7533 | }; |
@@ -7111,7 +7542,6 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
7111 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 7542 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
7112 | /* The multiple "Capture Source" controls confuse alsamixer | 7543 | /* The multiple "Capture Source" controls confuse alsamixer |
7113 | * So call somewhat different.. | 7544 | * So call somewhat different.. |
7114 | * FIXME: the controls appear in the "playback" view! | ||
7115 | */ | 7545 | */ |
7116 | /* .name = "Capture Source", */ | 7546 | /* .name = "Capture Source", */ |
7117 | .name = "Input Source", | 7547 | .name = "Input Source", |
@@ -7130,6 +7560,7 @@ static struct snd_kcontrol_new alc883_capture_mixer[] = { | |||
7130 | /* pcm configuration: identiacal with ALC880 */ | 7560 | /* pcm configuration: identiacal with ALC880 */ |
7131 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback | 7561 | #define alc883_pcm_analog_playback alc880_pcm_analog_playback |
7132 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture | 7562 | #define alc883_pcm_analog_capture alc880_pcm_analog_capture |
7563 | #define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
7133 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback | 7564 | #define alc883_pcm_digital_playback alc880_pcm_digital_playback |
7134 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture | 7565 | #define alc883_pcm_digital_capture alc880_pcm_digital_capture |
7135 | 7566 | ||
@@ -7154,53 +7585,58 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
7154 | [ALC883_HAIER_W66] = "haier-w66", | 7585 | [ALC883_HAIER_W66] = "haier-w66", |
7155 | [ALC888_6ST_HP] = "6stack-hp", | 7586 | [ALC888_6ST_HP] = "6stack-hp", |
7156 | [ALC888_3ST_HP] = "3stack-hp", | 7587 | [ALC888_3ST_HP] = "3stack-hp", |
7588 | [ALC888_6ST_DELL] = "6stack-dell", | ||
7589 | [ALC883_MITAC] = "mitac", | ||
7157 | [ALC883_AUTO] = "auto", | 7590 | [ALC883_AUTO] = "auto", |
7158 | }; | 7591 | }; |
7159 | 7592 | ||
7160 | static struct snd_pci_quirk alc883_cfg_tbl[] = { | 7593 | static struct snd_pci_quirk alc883_cfg_tbl[] = { |
7161 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), | 7594 | SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), |
7595 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), | ||
7596 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), | ||
7597 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), | ||
7598 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */ | ||
7599 | SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), | ||
7162 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), | 7600 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), |
7163 | SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), | 7601 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), |
7164 | SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), | 7602 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), |
7603 | SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP), | ||
7604 | SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), | ||
7165 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), | 7605 | SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), |
7606 | SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), | ||
7607 | SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), | ||
7608 | SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), | ||
7166 | SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), | 7609 | SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), |
7167 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), | ||
7168 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), | ||
7169 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), | ||
7170 | SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), | ||
7171 | SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), | ||
7172 | SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), | 7610 | SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), |
7611 | SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), | ||
7173 | SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), | 7612 | SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), |
7174 | SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), | 7613 | SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), |
7175 | SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), | ||
7176 | SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), | 7614 | SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), |
7177 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), | 7615 | SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG), |
7178 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), | 7616 | SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG), |
7179 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), | 7617 | SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG), |
7618 | SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG), | ||
7180 | SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), | 7619 | SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG), |
7181 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), | 7620 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), |
7182 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), | 7621 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), |
7183 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), | 7622 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), |
7623 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), | ||
7624 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), | ||
7625 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), | ||
7626 | SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), | ||
7627 | SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), | ||
7184 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), | 7628 | SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), |
7185 | SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), | 7629 | SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), |
7186 | SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE), | 7630 | SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD), |
7187 | SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE), | ||
7188 | SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), | ||
7189 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), | 7631 | SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), |
7190 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), | 7632 | SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), |
7191 | SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), | ||
7192 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | ||
7193 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), | 7633 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch), |
7194 | SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), | ||
7195 | SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), | 7634 | SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7196 | SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP), | 7635 | SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7197 | SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), | 7636 | SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763), |
7198 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), | ||
7199 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), | 7637 | SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2), |
7200 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), | 7638 | SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), |
7201 | SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763), | 7639 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), |
7202 | SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), | ||
7203 | SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), | ||
7204 | {} | 7640 | {} |
7205 | }; | 7641 | }; |
7206 | 7642 | ||
@@ -7435,6 +7871,34 @@ static struct alc_config_preset alc883_presets[] = { | |||
7435 | .need_dac_fix = 1, | 7871 | .need_dac_fix = 1, |
7436 | .input_mux = &alc883_capture_source, | 7872 | .input_mux = &alc883_capture_source, |
7437 | }, | 7873 | }, |
7874 | [ALC888_6ST_DELL] = { | ||
7875 | .mixers = { alc888_6st_dell_mixer, alc883_chmode_mixer }, | ||
7876 | .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs }, | ||
7877 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7878 | .dac_nids = alc883_dac_nids, | ||
7879 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
7880 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7881 | .adc_nids = alc883_adc_nids, | ||
7882 | .dig_in_nid = ALC883_DIGIN_NID, | ||
7883 | .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), | ||
7884 | .channel_mode = alc883_sixstack_modes, | ||
7885 | .input_mux = &alc883_capture_source, | ||
7886 | .unsol_event = alc888_6st_dell_unsol_event, | ||
7887 | .init_hook = alc888_6st_dell_front_automute, | ||
7888 | }, | ||
7889 | [ALC883_MITAC] = { | ||
7890 | .mixers = { alc883_mitac_mixer }, | ||
7891 | .init_verbs = { alc883_init_verbs, alc883_mitac_verbs }, | ||
7892 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
7893 | .dac_nids = alc883_dac_nids, | ||
7894 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
7895 | .adc_nids = alc883_adc_nids, | ||
7896 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
7897 | .channel_mode = alc883_3ST_2ch_modes, | ||
7898 | .input_mux = &alc883_capture_source, | ||
7899 | .unsol_event = alc883_mitac_unsol_event, | ||
7900 | .init_hook = alc883_mitac_automute, | ||
7901 | }, | ||
7438 | }; | 7902 | }; |
7439 | 7903 | ||
7440 | 7904 | ||
@@ -7582,6 +8046,7 @@ static int patch_alc883(struct hda_codec *codec) | |||
7582 | spec->stream_name_analog = "ALC883 Analog"; | 8046 | spec->stream_name_analog = "ALC883 Analog"; |
7583 | spec->stream_analog_playback = &alc883_pcm_analog_playback; | 8047 | spec->stream_analog_playback = &alc883_pcm_analog_playback; |
7584 | spec->stream_analog_capture = &alc883_pcm_analog_capture; | 8048 | spec->stream_analog_capture = &alc883_pcm_analog_capture; |
8049 | spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; | ||
7585 | 8050 | ||
7586 | spec->stream_name_digital = "ALC883 Digital"; | 8051 | spec->stream_name_digital = "ALC883 Digital"; |
7587 | spec->stream_digital_playback = &alc883_pcm_digital_playback; | 8052 | spec->stream_digital_playback = &alc883_pcm_digital_playback; |
@@ -7592,6 +8057,8 @@ static int patch_alc883(struct hda_codec *codec) | |||
7592 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 8057 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); |
7593 | } | 8058 | } |
7594 | 8059 | ||
8060 | spec->vmaster_nid = 0x0c; | ||
8061 | |||
7595 | codec->patch_ops = alc_patch_ops; | 8062 | codec->patch_ops = alc_patch_ops; |
7596 | if (board_config == ALC883_AUTO) | 8063 | if (board_config == ALC883_AUTO) |
7597 | spec->init_hook = alc883_auto_init; | 8064 | spec->init_hook = alc883_auto_init; |
@@ -7659,13 +8126,99 @@ static struct snd_kcontrol_new alc262_hippo1_mixer[] = { | |||
7659 | { } /* end */ | 8126 | { } /* end */ |
7660 | }; | 8127 | }; |
7661 | 8128 | ||
8129 | /* update HP, line and mono-out pins according to the master switch */ | ||
8130 | static void alc262_hp_master_update(struct hda_codec *codec) | ||
8131 | { | ||
8132 | struct alc_spec *spec = codec->spec; | ||
8133 | int val = spec->master_sw; | ||
8134 | |||
8135 | /* HP & line-out */ | ||
8136 | snd_hda_codec_write_cache(codec, 0x1b, 0, | ||
8137 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8138 | val ? PIN_HP : 0); | ||
8139 | snd_hda_codec_write_cache(codec, 0x15, 0, | ||
8140 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8141 | val ? PIN_HP : 0); | ||
8142 | /* mono (speaker) depending on the HP jack sense */ | ||
8143 | val = val && !spec->jack_present; | ||
8144 | snd_hda_codec_write_cache(codec, 0x16, 0, | ||
8145 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8146 | val ? PIN_OUT : 0); | ||
8147 | } | ||
8148 | |||
8149 | static void alc262_hp_bpc_automute(struct hda_codec *codec) | ||
8150 | { | ||
8151 | struct alc_spec *spec = codec->spec; | ||
8152 | unsigned int presence; | ||
8153 | presence = snd_hda_codec_read(codec, 0x1b, 0, | ||
8154 | AC_VERB_GET_PIN_SENSE, 0); | ||
8155 | spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); | ||
8156 | alc262_hp_master_update(codec); | ||
8157 | } | ||
8158 | |||
8159 | static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res) | ||
8160 | { | ||
8161 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8162 | return; | ||
8163 | alc262_hp_bpc_automute(codec); | ||
8164 | } | ||
8165 | |||
8166 | static void alc262_hp_wildwest_automute(struct hda_codec *codec) | ||
8167 | { | ||
8168 | struct alc_spec *spec = codec->spec; | ||
8169 | unsigned int presence; | ||
8170 | presence = snd_hda_codec_read(codec, 0x15, 0, | ||
8171 | AC_VERB_GET_PIN_SENSE, 0); | ||
8172 | spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); | ||
8173 | alc262_hp_master_update(codec); | ||
8174 | } | ||
8175 | |||
8176 | static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, | ||
8177 | unsigned int res) | ||
8178 | { | ||
8179 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8180 | return; | ||
8181 | alc262_hp_wildwest_automute(codec); | ||
8182 | } | ||
8183 | |||
8184 | static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, | ||
8185 | struct snd_ctl_elem_value *ucontrol) | ||
8186 | { | ||
8187 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8188 | struct alc_spec *spec = codec->spec; | ||
8189 | *ucontrol->value.integer.value = spec->master_sw; | ||
8190 | return 0; | ||
8191 | } | ||
8192 | |||
8193 | static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
8194 | struct snd_ctl_elem_value *ucontrol) | ||
8195 | { | ||
8196 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
8197 | struct alc_spec *spec = codec->spec; | ||
8198 | int val = !!*ucontrol->value.integer.value; | ||
8199 | |||
8200 | if (val == spec->master_sw) | ||
8201 | return 0; | ||
8202 | spec->master_sw = val; | ||
8203 | alc262_hp_master_update(codec); | ||
8204 | return 1; | ||
8205 | } | ||
8206 | |||
7662 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 8207 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
8208 | { | ||
8209 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8210 | .name = "Master Playback Switch", | ||
8211 | .info = snd_ctl_boolean_mono_info, | ||
8212 | .get = alc262_hp_master_sw_get, | ||
8213 | .put = alc262_hp_master_sw_put, | ||
8214 | }, | ||
7663 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 8215 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
7664 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 8216 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
7665 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 8217 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
7666 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 8218 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, |
7667 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 8219 | HDA_OUTPUT), |
7668 | 8220 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, | |
8221 | HDA_OUTPUT), | ||
7669 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 8222 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
7670 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 8223 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
7671 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 8224 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -7684,12 +8237,21 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | |||
7684 | }; | 8237 | }; |
7685 | 8238 | ||
7686 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { | 8239 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { |
8240 | { | ||
8241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
8242 | .name = "Master Playback Switch", | ||
8243 | .info = snd_ctl_boolean_mono_info, | ||
8244 | .get = alc262_hp_master_sw_get, | ||
8245 | .put = alc262_hp_master_sw_put, | ||
8246 | }, | ||
7687 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 8247 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
7688 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 8248 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
7689 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 8249 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
7690 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 8250 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
7691 | HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), | 8251 | HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0, |
7692 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | 8252 | HDA_OUTPUT), |
8253 | HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0, | ||
8254 | HDA_OUTPUT), | ||
7693 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), | 8255 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT), |
7694 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), | 8256 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT), |
7695 | HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), | 8257 | HDA_CODEC_VOLUME("Front Mic Boost", 0x1a, 0, HDA_INPUT), |
@@ -7709,6 +8271,85 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { | |||
7709 | { } /* end */ | 8271 | { } /* end */ |
7710 | }; | 8272 | }; |
7711 | 8273 | ||
8274 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
8275 | static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) | ||
8276 | { | ||
8277 | struct alc_spec *spec = codec->spec; | ||
8278 | |||
8279 | if (force || !spec->sense_updated) { | ||
8280 | unsigned int present; | ||
8281 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
8282 | AC_VERB_GET_PIN_SENSE, 0); | ||
8283 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
8284 | spec->sense_updated = 1; | ||
8285 | } | ||
8286 | snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
8287 | spec->jack_present ? HDA_AMP_MUTE : 0); | ||
8288 | } | ||
8289 | |||
8290 | static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, | ||
8291 | unsigned int res) | ||
8292 | { | ||
8293 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8294 | return; | ||
8295 | alc262_hp_t5735_automute(codec, 1); | ||
8296 | } | ||
8297 | |||
8298 | static void alc262_hp_t5735_init_hook(struct hda_codec *codec) | ||
8299 | { | ||
8300 | alc262_hp_t5735_automute(codec, 1); | ||
8301 | } | ||
8302 | |||
8303 | static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { | ||
8304 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8305 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
8306 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
8307 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
8308 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
8309 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
8310 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
8311 | { } /* end */ | ||
8312 | }; | ||
8313 | |||
8314 | static struct hda_verb alc262_hp_t5735_verbs[] = { | ||
8315 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8316 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8317 | |||
8318 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
8319 | { } | ||
8320 | }; | ||
8321 | |||
8322 | static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = { | ||
8323 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8324 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
8325 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT), | ||
8326 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT), | ||
8327 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
8328 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
8329 | { } /* end */ | ||
8330 | }; | ||
8331 | |||
8332 | static struct hda_verb alc262_hp_rp5700_verbs[] = { | ||
8333 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8334 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8335 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8336 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8337 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
8338 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8339 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8340 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8341 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, | ||
8342 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))}, | ||
8343 | {} | ||
8344 | }; | ||
8345 | |||
8346 | static struct hda_input_mux alc262_hp_rp5700_capture_source = { | ||
8347 | .num_items = 1, | ||
8348 | .items = { | ||
8349 | { "Line", 0x1 }, | ||
8350 | }, | ||
8351 | }; | ||
8352 | |||
7712 | /* bind hp and internal speaker mute (with plug check) */ | 8353 | /* bind hp and internal speaker mute (with plug check) */ |
7713 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, | 8354 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, |
7714 | struct snd_ctl_elem_value *ucontrol) | 8355 | struct snd_ctl_elem_value *ucontrol) |
@@ -8082,6 +8723,72 @@ static struct hda_verb alc262_benq_t31_EAPD_verbs[] = { | |||
8082 | {} | 8723 | {} |
8083 | }; | 8724 | }; |
8084 | 8725 | ||
8726 | /* Samsung Q1 Ultra Vista model setup */ | ||
8727 | static struct snd_kcontrol_new alc262_ultra_mixer[] = { | ||
8728 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8729 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
8730 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
8731 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
8732 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
8733 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), | ||
8734 | { } /* end */ | ||
8735 | }; | ||
8736 | |||
8737 | static struct hda_verb alc262_ultra_verbs[] = { | ||
8738 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
8739 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8740 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
8741 | /* Mic is on Node 0x19 */ | ||
8742 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, | ||
8743 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8744 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8745 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8746 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8747 | {0x24, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8748 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8749 | {} | ||
8750 | }; | ||
8751 | |||
8752 | static struct hda_input_mux alc262_ultra_capture_source = { | ||
8753 | .num_items = 1, | ||
8754 | .items = { | ||
8755 | { "Mic", 0x1 }, | ||
8756 | }, | ||
8757 | }; | ||
8758 | |||
8759 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
8760 | static void alc262_ultra_automute(struct hda_codec *codec) | ||
8761 | { | ||
8762 | struct alc_spec *spec = codec->spec; | ||
8763 | unsigned int mute; | ||
8764 | unsigned int present; | ||
8765 | |||
8766 | /* need to execute and sync at first */ | ||
8767 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
8768 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
8769 | AC_VERB_GET_PIN_SENSE, 0); | ||
8770 | spec->jack_present = (present & 0x80000000) != 0; | ||
8771 | if (spec->jack_present) { | ||
8772 | /* mute internal speaker */ | ||
8773 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8774 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8775 | } else { | ||
8776 | /* unmute internal speaker if necessary */ | ||
8777 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
8778 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8779 | HDA_AMP_MUTE, mute); | ||
8780 | } | ||
8781 | } | ||
8782 | |||
8783 | /* unsolicited event for HP jack sensing */ | ||
8784 | static void alc262_ultra_unsol_event(struct hda_codec *codec, | ||
8785 | unsigned int res) | ||
8786 | { | ||
8787 | if ((res >> 26) != ALC880_HP_EVENT) | ||
8788 | return; | ||
8789 | alc262_ultra_automute(codec); | ||
8790 | } | ||
8791 | |||
8085 | /* add playback controls from the parsed DAC table */ | 8792 | /* add playback controls from the parsed DAC table */ |
8086 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, | 8793 | static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, |
8087 | const struct auto_pin_cfg *cfg) | 8794 | const struct auto_pin_cfg *cfg) |
@@ -8269,7 +8976,7 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
8269 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 8976 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
8270 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | 8977 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
8271 | 8978 | ||
8272 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | 8979 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
8273 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 8980 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
8274 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 8981 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, |
8275 | 8982 | ||
@@ -8311,6 +9018,8 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
8311 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 9018 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, |
8312 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 9019 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, |
8313 | 9020 | ||
9021 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9022 | |||
8314 | { } | 9023 | { } |
8315 | }; | 9024 | }; |
8316 | 9025 | ||
@@ -8405,6 +9114,8 @@ static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = { | |||
8405 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ | 9114 | /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */ |
8406 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, | 9115 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, |
8407 | 9116 | ||
9117 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9118 | |||
8408 | { } | 9119 | { } |
8409 | }; | 9120 | }; |
8410 | 9121 | ||
@@ -8484,39 +9195,49 @@ static const char *alc262_models[ALC262_MODEL_LAST] = { | |||
8484 | [ALC262_FUJITSU] = "fujitsu", | 9195 | [ALC262_FUJITSU] = "fujitsu", |
8485 | [ALC262_HP_BPC] = "hp-bpc", | 9196 | [ALC262_HP_BPC] = "hp-bpc", |
8486 | [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", | 9197 | [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000", |
9198 | [ALC262_HP_TC_T5735] = "hp-tc-t5735", | ||
9199 | [ALC262_HP_RP5700] = "hp-rp5700", | ||
8487 | [ALC262_BENQ_ED8] = "benq", | 9200 | [ALC262_BENQ_ED8] = "benq", |
8488 | [ALC262_BENQ_T31] = "benq-t31", | 9201 | [ALC262_BENQ_T31] = "benq-t31", |
8489 | [ALC262_SONY_ASSAMD] = "sony-assamd", | 9202 | [ALC262_SONY_ASSAMD] = "sony-assamd", |
9203 | [ALC262_ULTRA] = "ultra", | ||
8490 | [ALC262_AUTO] = "auto", | 9204 | [ALC262_AUTO] = "auto", |
8491 | }; | 9205 | }; |
8492 | 9206 | ||
8493 | static struct snd_pci_quirk alc262_cfg_tbl[] = { | 9207 | static struct snd_pci_quirk alc262_cfg_tbl[] = { |
8494 | SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), | 9208 | SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO), |
8495 | SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), | 9209 | SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC), |
8496 | SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), | ||
8497 | SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), | 9210 | SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC), |
8498 | SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC), | ||
8499 | SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), | ||
8500 | SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC), | ||
8501 | SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), | ||
8502 | SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), | 9211 | SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC), |
9212 | SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC), | ||
9213 | SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC), | ||
9214 | SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC), | ||
9215 | SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC), | ||
9216 | SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC), | ||
8503 | SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), | 9217 | SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL), |
8504 | SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8505 | SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8506 | SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8507 | SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9218 | SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9219 | SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8508 | SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9220 | SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9221 | SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8509 | SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9222 | SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9223 | SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL), | ||
8510 | SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), | 9224 | SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF), |
9225 | SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC), | ||
9226 | SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC), | ||
9227 | SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC), | ||
9228 | SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735", | ||
9229 | ALC262_HP_TC_T5735), | ||
9230 | SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700), | ||
9231 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8511 | SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), | 9232 | SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO), |
9233 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
9234 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
9235 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | ||
8512 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), | 9236 | SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU), |
8513 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), | 9237 | SND_PCI_QUIRK(0x144d, 0xc032, "Samsung Q1 Ultra", ALC262_ULTRA), |
8514 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), | 9238 | SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8), |
8515 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), | 9239 | SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31), |
8516 | SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), | 9240 | SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1), |
8517 | SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD), | ||
8518 | SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8519 | SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD), | ||
8520 | {} | 9241 | {} |
8521 | }; | 9242 | }; |
8522 | 9243 | ||
@@ -8579,6 +9300,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
8579 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9300 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8580 | .channel_mode = alc262_modes, | 9301 | .channel_mode = alc262_modes, |
8581 | .input_mux = &alc262_HP_capture_source, | 9302 | .input_mux = &alc262_HP_capture_source, |
9303 | .unsol_event = alc262_hp_bpc_unsol_event, | ||
9304 | .init_hook = alc262_hp_bpc_automute, | ||
8582 | }, | 9305 | }, |
8583 | [ALC262_HP_BPC_D7000_WF] = { | 9306 | [ALC262_HP_BPC_D7000_WF] = { |
8584 | .mixers = { alc262_HP_BPC_WildWest_mixer }, | 9307 | .mixers = { alc262_HP_BPC_WildWest_mixer }, |
@@ -8589,6 +9312,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
8589 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9312 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8590 | .channel_mode = alc262_modes, | 9313 | .channel_mode = alc262_modes, |
8591 | .input_mux = &alc262_HP_D7000_capture_source, | 9314 | .input_mux = &alc262_HP_D7000_capture_source, |
9315 | .unsol_event = alc262_hp_wildwest_unsol_event, | ||
9316 | .init_hook = alc262_hp_wildwest_automute, | ||
8592 | }, | 9317 | }, |
8593 | [ALC262_HP_BPC_D7000_WL] = { | 9318 | [ALC262_HP_BPC_D7000_WL] = { |
8594 | .mixers = { alc262_HP_BPC_WildWest_mixer, | 9319 | .mixers = { alc262_HP_BPC_WildWest_mixer, |
@@ -8600,7 +9325,30 @@ static struct alc_config_preset alc262_presets[] = { | |||
8600 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 9325 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
8601 | .channel_mode = alc262_modes, | 9326 | .channel_mode = alc262_modes, |
8602 | .input_mux = &alc262_HP_D7000_capture_source, | 9327 | .input_mux = &alc262_HP_D7000_capture_source, |
9328 | .unsol_event = alc262_hp_wildwest_unsol_event, | ||
9329 | .init_hook = alc262_hp_wildwest_automute, | ||
9330 | }, | ||
9331 | [ALC262_HP_TC_T5735] = { | ||
9332 | .mixers = { alc262_hp_t5735_mixer }, | ||
9333 | .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs }, | ||
9334 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9335 | .dac_nids = alc262_dac_nids, | ||
9336 | .hp_nid = 0x03, | ||
9337 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9338 | .channel_mode = alc262_modes, | ||
9339 | .input_mux = &alc262_capture_source, | ||
9340 | .unsol_event = alc262_hp_t5735_unsol_event, | ||
9341 | .init_hook = alc262_hp_t5735_init_hook, | ||
8603 | }, | 9342 | }, |
9343 | [ALC262_HP_RP5700] = { | ||
9344 | .mixers = { alc262_hp_rp5700_mixer }, | ||
9345 | .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs }, | ||
9346 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9347 | .dac_nids = alc262_dac_nids, | ||
9348 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9349 | .channel_mode = alc262_modes, | ||
9350 | .input_mux = &alc262_hp_rp5700_capture_source, | ||
9351 | }, | ||
8604 | [ALC262_BENQ_ED8] = { | 9352 | [ALC262_BENQ_ED8] = { |
8605 | .mixers = { alc262_base_mixer }, | 9353 | .mixers = { alc262_base_mixer }, |
8606 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, | 9354 | .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs }, |
@@ -8635,6 +9383,19 @@ static struct alc_config_preset alc262_presets[] = { | |||
8635 | .unsol_event = alc262_hippo_unsol_event, | 9383 | .unsol_event = alc262_hippo_unsol_event, |
8636 | .init_hook = alc262_hippo_automute, | 9384 | .init_hook = alc262_hippo_automute, |
8637 | }, | 9385 | }, |
9386 | [ALC262_ULTRA] = { | ||
9387 | .mixers = { alc262_ultra_mixer }, | ||
9388 | .init_verbs = { alc262_init_verbs, alc262_ultra_verbs }, | ||
9389 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | ||
9390 | .dac_nids = alc262_dac_nids, | ||
9391 | .hp_nid = 0x03, | ||
9392 | .dig_out_nid = ALC262_DIGOUT_NID, | ||
9393 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | ||
9394 | .channel_mode = alc262_modes, | ||
9395 | .input_mux = &alc262_ultra_capture_source, | ||
9396 | .unsol_event = alc262_ultra_unsol_event, | ||
9397 | .init_hook = alc262_ultra_automute, | ||
9398 | }, | ||
8638 | }; | 9399 | }; |
8639 | 9400 | ||
8640 | static int patch_alc262(struct hda_codec *codec) | 9401 | static int patch_alc262(struct hda_codec *codec) |
@@ -8716,6 +9477,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
8716 | } | 9477 | } |
8717 | } | 9478 | } |
8718 | 9479 | ||
9480 | spec->vmaster_nid = 0x0c; | ||
9481 | |||
8719 | codec->patch_ops = alc_patch_ops; | 9482 | codec->patch_ops = alc_patch_ops; |
8720 | if (board_config == ALC262_AUTO) | 9483 | if (board_config == ALC262_AUTO) |
8721 | spec->init_hook = alc262_auto_init; | 9484 | spec->init_hook = alc262_auto_init; |
@@ -8873,6 +9636,49 @@ static void alc268_acer_init_hook(struct hda_codec *codec) | |||
8873 | alc268_acer_automute(codec, 1); | 9636 | alc268_acer_automute(codec, 1); |
8874 | } | 9637 | } |
8875 | 9638 | ||
9639 | static struct snd_kcontrol_new alc268_dell_mixer[] = { | ||
9640 | /* output mixer control */ | ||
9641 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
9642 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
9643 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
9644 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
9645 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
9646 | HDA_CODEC_VOLUME("Internal Mic Boost", 0x19, 0, HDA_INPUT), | ||
9647 | { } | ||
9648 | }; | ||
9649 | |||
9650 | static struct hda_verb alc268_dell_verbs[] = { | ||
9651 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
9652 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
9653 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
9654 | { } | ||
9655 | }; | ||
9656 | |||
9657 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
9658 | static void alc268_dell_automute(struct hda_codec *codec) | ||
9659 | { | ||
9660 | unsigned int present; | ||
9661 | unsigned int mute; | ||
9662 | |||
9663 | present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
9664 | if (present & 0x80000000) | ||
9665 | mute = HDA_AMP_MUTE; | ||
9666 | else | ||
9667 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
9668 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9669 | HDA_AMP_MUTE, mute); | ||
9670 | } | ||
9671 | |||
9672 | static void alc268_dell_unsol_event(struct hda_codec *codec, | ||
9673 | unsigned int res) | ||
9674 | { | ||
9675 | if ((res >> 26) != ALC880_HP_EVENT) | ||
9676 | return; | ||
9677 | alc268_dell_automute(codec); | ||
9678 | } | ||
9679 | |||
9680 | #define alc268_dell_init_hook alc268_dell_automute | ||
9681 | |||
8876 | /* | 9682 | /* |
8877 | * generic initialization of ADC, input mixers and output mixers | 9683 | * generic initialization of ADC, input mixers and output mixers |
8878 | */ | 9684 | */ |
@@ -8915,19 +9721,13 @@ static struct hda_verb alc268_base_init_verbs[] = { | |||
8915 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | 9721 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
8916 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 9722 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
8917 | 9723 | ||
8918 | /* FIXME: use matrix-type input source selection */ | 9724 | /* Unmute Selector 23h,24h and set the default input to mic-in */ |
8919 | /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */ | 9725 | |
8920 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | 9726 | {0x23, AC_VERB_SET_CONNECT_SEL, 0x00}, |
8921 | /* Input mixer2 */ | 9727 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
8922 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 9728 | {0x24, AC_VERB_SET_CONNECT_SEL, 0x00}, |
8923 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 9729 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
8924 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
8925 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
8926 | 9730 | ||
8927 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | ||
8928 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | ||
8929 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | ||
8930 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | ||
8931 | { } | 9731 | { } |
8932 | }; | 9732 | }; |
8933 | 9733 | ||
@@ -8972,29 +9772,14 @@ static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
8972 | { | 9772 | { |
8973 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 9773 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
8974 | struct alc_spec *spec = codec->spec; | 9774 | struct alc_spec *spec = codec->spec; |
8975 | const struct hda_input_mux *imux = spec->input_mux; | 9775 | |
8976 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 9776 | unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
8977 | static hda_nid_t capture_mixers[3] = { 0x23, 0x24 }; | 9777 | static hda_nid_t capture_mixers[3] = { 0x23, 0x24 }; |
8978 | hda_nid_t nid = capture_mixers[adc_idx]; | 9778 | hda_nid_t nid = capture_mixers[adc_idx]; |
8979 | unsigned int *cur_val = &spec->cur_mux[adc_idx]; | ||
8980 | unsigned int i, idx; | ||
8981 | 9779 | ||
8982 | idx = ucontrol->value.enumerated.item[0]; | 9780 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
8983 | if (idx >= imux->num_items) | 9781 | nid, |
8984 | idx = imux->num_items - 1; | 9782 | &spec->cur_mux[adc_idx]); |
8985 | if (*cur_val == idx) | ||
8986 | return 0; | ||
8987 | for (i = 0; i < imux->num_items; i++) { | ||
8988 | unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE; | ||
8989 | snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, | ||
8990 | imux->items[i].index, | ||
8991 | HDA_AMP_MUTE, v); | ||
8992 | snd_hda_codec_write_cache(codec, nid, 0, | ||
8993 | AC_VERB_SET_CONNECT_SEL, | ||
8994 | idx ); | ||
8995 | } | ||
8996 | *cur_val = idx; | ||
8997 | return 1; | ||
8998 | } | 9783 | } |
8999 | 9784 | ||
9000 | static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { | 9785 | static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { |
@@ -9004,7 +9789,6 @@ static struct snd_kcontrol_new alc268_capture_alt_mixer[] = { | |||
9004 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 9789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
9005 | /* The multiple "Capture Source" controls confuse alsamixer | 9790 | /* The multiple "Capture Source" controls confuse alsamixer |
9006 | * So call somewhat different.. | 9791 | * So call somewhat different.. |
9007 | * FIXME: the controls appear in the "playback" view! | ||
9008 | */ | 9792 | */ |
9009 | /* .name = "Capture Source", */ | 9793 | /* .name = "Capture Source", */ |
9010 | .name = "Input Source", | 9794 | .name = "Input Source", |
@@ -9025,7 +9809,6 @@ static struct snd_kcontrol_new alc268_capture_mixer[] = { | |||
9025 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 9809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
9026 | /* The multiple "Capture Source" controls confuse alsamixer | 9810 | /* The multiple "Capture Source" controls confuse alsamixer |
9027 | * So call somewhat different.. | 9811 | * So call somewhat different.. |
9028 | * FIXME: the controls appear in the "playback" view! | ||
9029 | */ | 9812 | */ |
9030 | /* .name = "Capture Source", */ | 9813 | /* .name = "Capture Source", */ |
9031 | .name = "Input Source", | 9814 | .name = "Input Source", |
@@ -9047,6 +9830,61 @@ static struct hda_input_mux alc268_capture_source = { | |||
9047 | }, | 9830 | }, |
9048 | }; | 9831 | }; |
9049 | 9832 | ||
9833 | #ifdef CONFIG_SND_DEBUG | ||
9834 | static struct snd_kcontrol_new alc268_test_mixer[] = { | ||
9835 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
9836 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
9837 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), | ||
9838 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
9839 | |||
9840 | /* Volume widgets */ | ||
9841 | HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
9842 | HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
9843 | HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT), | ||
9844 | HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT), | ||
9845 | HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT), | ||
9846 | HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT), | ||
9847 | HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT), | ||
9848 | HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT), | ||
9849 | HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT), | ||
9850 | HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT), | ||
9851 | HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT), | ||
9852 | HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT), | ||
9853 | HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT), | ||
9854 | /* The below appears problematic on some hardwares */ | ||
9855 | /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/ | ||
9856 | HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT), | ||
9857 | HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT), | ||
9858 | HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT), | ||
9859 | HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT), | ||
9860 | |||
9861 | /* Modes for retasking pin widgets */ | ||
9862 | ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT), | ||
9863 | ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT), | ||
9864 | ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT), | ||
9865 | ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT), | ||
9866 | |||
9867 | /* Controls for GPIO pins, assuming they are configured as outputs */ | ||
9868 | ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), | ||
9869 | ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), | ||
9870 | ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), | ||
9871 | ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), | ||
9872 | |||
9873 | /* Switches to allow the digital SPDIF output pin to be enabled. | ||
9874 | * The ALC268 does not have an SPDIF input. | ||
9875 | */ | ||
9876 | ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01), | ||
9877 | |||
9878 | /* A switch allowing EAPD to be enabled. Some laptops seem to use | ||
9879 | * this output to turn on an external amplifier. | ||
9880 | */ | ||
9881 | ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02), | ||
9882 | ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02), | ||
9883 | |||
9884 | { } /* end */ | ||
9885 | }; | ||
9886 | #endif | ||
9887 | |||
9050 | /* create input playback/capture controls for the given pin */ | 9888 | /* create input playback/capture controls for the given pin */ |
9051 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, | 9889 | static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, |
9052 | const char *ctlname, int idx) | 9890 | const char *ctlname, int idx) |
@@ -9194,6 +10032,7 @@ static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec) | |||
9194 | /* pcm configuration: identiacal with ALC880 */ | 10032 | /* pcm configuration: identiacal with ALC880 */ |
9195 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback | 10033 | #define alc268_pcm_analog_playback alc880_pcm_analog_playback |
9196 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture | 10034 | #define alc268_pcm_analog_capture alc880_pcm_analog_capture |
10035 | #define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture | ||
9197 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback | 10036 | #define alc268_pcm_digital_playback alc880_pcm_digital_playback |
9198 | 10037 | ||
9199 | /* | 10038 | /* |
@@ -9259,16 +10098,23 @@ static const char *alc268_models[ALC268_MODEL_LAST] = { | |||
9259 | [ALC268_3ST] = "3stack", | 10098 | [ALC268_3ST] = "3stack", |
9260 | [ALC268_TOSHIBA] = "toshiba", | 10099 | [ALC268_TOSHIBA] = "toshiba", |
9261 | [ALC268_ACER] = "acer", | 10100 | [ALC268_ACER] = "acer", |
10101 | [ALC268_DELL] = "dell", | ||
10102 | #ifdef CONFIG_SND_DEBUG | ||
10103 | [ALC268_TEST] = "test", | ||
10104 | #endif | ||
9262 | [ALC268_AUTO] = "auto", | 10105 | [ALC268_AUTO] = "auto", |
9263 | }; | 10106 | }; |
9264 | 10107 | ||
9265 | static struct snd_pci_quirk alc268_cfg_tbl[] = { | 10108 | static struct snd_pci_quirk alc268_cfg_tbl[] = { |
10109 | SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), | ||
10110 | SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER), | ||
10111 | SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), | ||
10112 | SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER), | ||
10113 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), | ||
10114 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | ||
9266 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), | 10115 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), |
9267 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), | 10116 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), |
9268 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), | 10117 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), |
9269 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | ||
9270 | SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER), | ||
9271 | SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER), | ||
9272 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), | 10118 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), |
9273 | {} | 10119 | {} |
9274 | }; | 10120 | }; |
@@ -9317,6 +10163,35 @@ static struct alc_config_preset alc268_presets[] = { | |||
9317 | .unsol_event = alc268_acer_unsol_event, | 10163 | .unsol_event = alc268_acer_unsol_event, |
9318 | .init_hook = alc268_acer_init_hook, | 10164 | .init_hook = alc268_acer_init_hook, |
9319 | }, | 10165 | }, |
10166 | [ALC268_DELL] = { | ||
10167 | .mixers = { alc268_dell_mixer }, | ||
10168 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
10169 | alc268_dell_verbs }, | ||
10170 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
10171 | .dac_nids = alc268_dac_nids, | ||
10172 | .hp_nid = 0x02, | ||
10173 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
10174 | .channel_mode = alc268_modes, | ||
10175 | .unsol_event = alc268_dell_unsol_event, | ||
10176 | .init_hook = alc268_dell_init_hook, | ||
10177 | .input_mux = &alc268_capture_source, | ||
10178 | }, | ||
10179 | #ifdef CONFIG_SND_DEBUG | ||
10180 | [ALC268_TEST] = { | ||
10181 | .mixers = { alc268_test_mixer, alc268_capture_mixer }, | ||
10182 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | ||
10183 | alc268_volume_init_verbs }, | ||
10184 | .num_dacs = ARRAY_SIZE(alc268_dac_nids), | ||
10185 | .dac_nids = alc268_dac_nids, | ||
10186 | .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt), | ||
10187 | .adc_nids = alc268_adc_nids_alt, | ||
10188 | .hp_nid = 0x03, | ||
10189 | .dig_out_nid = ALC268_DIGOUT_NID, | ||
10190 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | ||
10191 | .channel_mode = alc268_modes, | ||
10192 | .input_mux = &alc268_capture_source, | ||
10193 | }, | ||
10194 | #endif | ||
9320 | }; | 10195 | }; |
9321 | 10196 | ||
9322 | static int patch_alc268(struct hda_codec *codec) | 10197 | static int patch_alc268(struct hda_codec *codec) |
@@ -9361,34 +10236,34 @@ static int patch_alc268(struct hda_codec *codec) | |||
9361 | spec->stream_name_analog = "ALC268 Analog"; | 10236 | spec->stream_name_analog = "ALC268 Analog"; |
9362 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 10237 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
9363 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 10238 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
10239 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | ||
9364 | 10240 | ||
9365 | spec->stream_name_digital = "ALC268 Digital"; | 10241 | spec->stream_name_digital = "ALC268 Digital"; |
9366 | spec->stream_digital_playback = &alc268_pcm_digital_playback; | 10242 | spec->stream_digital_playback = &alc268_pcm_digital_playback; |
9367 | 10243 | ||
9368 | if (board_config == ALC268_AUTO) { | 10244 | if (!spec->adc_nids && spec->input_mux) { |
9369 | if (!spec->adc_nids && spec->input_mux) { | 10245 | /* check whether NID 0x07 is valid */ |
9370 | /* check whether NID 0x07 is valid */ | 10246 | unsigned int wcap = get_wcaps(codec, 0x07); |
9371 | unsigned int wcap = get_wcaps(codec, 0x07); | 10247 | |
9372 | 10248 | /* get type */ | |
9373 | /* get type */ | 10249 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
9374 | wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 10250 | if (wcap != AC_WID_AUD_IN) { |
9375 | if (wcap != AC_WID_AUD_IN) { | 10251 | spec->adc_nids = alc268_adc_nids_alt; |
9376 | spec->adc_nids = alc268_adc_nids_alt; | 10252 | spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt); |
9377 | spec->num_adc_nids = | 10253 | spec->mixers[spec->num_mixers] = |
9378 | ARRAY_SIZE(alc268_adc_nids_alt); | ||
9379 | spec->mixers[spec->num_mixers] = | ||
9380 | alc268_capture_alt_mixer; | 10254 | alc268_capture_alt_mixer; |
9381 | spec->num_mixers++; | 10255 | spec->num_mixers++; |
9382 | } else { | 10256 | } else { |
9383 | spec->adc_nids = alc268_adc_nids; | 10257 | spec->adc_nids = alc268_adc_nids; |
9384 | spec->num_adc_nids = | 10258 | spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids); |
9385 | ARRAY_SIZE(alc268_adc_nids); | 10259 | spec->mixers[spec->num_mixers] = |
9386 | spec->mixers[spec->num_mixers] = | 10260 | alc268_capture_mixer; |
9387 | alc268_capture_mixer; | 10261 | spec->num_mixers++; |
9388 | spec->num_mixers++; | ||
9389 | } | ||
9390 | } | 10262 | } |
9391 | } | 10263 | } |
10264 | |||
10265 | spec->vmaster_nid = 0x02; | ||
10266 | |||
9392 | codec->patch_ops = alc_patch_ops; | 10267 | codec->patch_ops = alc_patch_ops; |
9393 | if (board_config == ALC268_AUTO) | 10268 | if (board_config == ALC268_AUTO) |
9394 | spec->init_hook = alc268_auto_init; | 10269 | spec->init_hook = alc268_auto_init; |
@@ -9397,6 +10272,360 @@ static int patch_alc268(struct hda_codec *codec) | |||
9397 | } | 10272 | } |
9398 | 10273 | ||
9399 | /* | 10274 | /* |
10275 | * ALC269 channel source setting (2 channel) | ||
10276 | */ | ||
10277 | #define ALC269_DIGOUT_NID ALC880_DIGOUT_NID | ||
10278 | |||
10279 | #define alc269_dac_nids alc260_dac_nids | ||
10280 | |||
10281 | static hda_nid_t alc269_adc_nids[1] = { | ||
10282 | /* ADC1 */ | ||
10283 | 0x07, | ||
10284 | }; | ||
10285 | |||
10286 | #define alc269_modes alc260_modes | ||
10287 | #define alc269_capture_source alc880_lg_lw_capture_source | ||
10288 | |||
10289 | static struct snd_kcontrol_new alc269_base_mixer[] = { | ||
10290 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
10291 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
10292 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
10293 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
10294 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
10295 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
10296 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
10297 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
10298 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
10299 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
10300 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
10301 | HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT), | ||
10302 | { } /* end */ | ||
10303 | }; | ||
10304 | |||
10305 | /* capture mixer elements */ | ||
10306 | static struct snd_kcontrol_new alc269_capture_mixer[] = { | ||
10307 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
10308 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
10309 | { | ||
10310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
10311 | /* The multiple "Capture Source" controls confuse alsamixer | ||
10312 | * So call somewhat different.. | ||
10313 | */ | ||
10314 | /* .name = "Capture Source", */ | ||
10315 | .name = "Input Source", | ||
10316 | .count = 1, | ||
10317 | .info = alc_mux_enum_info, | ||
10318 | .get = alc_mux_enum_get, | ||
10319 | .put = alc_mux_enum_put, | ||
10320 | }, | ||
10321 | { } /* end */ | ||
10322 | }; | ||
10323 | |||
10324 | /* | ||
10325 | * generic initialization of ADC, input mixers and output mixers | ||
10326 | */ | ||
10327 | static struct hda_verb alc269_init_verbs[] = { | ||
10328 | /* | ||
10329 | * Unmute ADC0 and set the default input to mic-in | ||
10330 | */ | ||
10331 | {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10332 | |||
10333 | /* Mute input amps (PCBeep, Line In, Mic 1 & Mic 2) of the | ||
10334 | * analog-loopback mixer widget | ||
10335 | * Note: PASD motherboards uses the Line In 2 as the input for | ||
10336 | * front panel mic (mic 2) | ||
10337 | */ | ||
10338 | /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ | ||
10339 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
10340 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
10341 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
10342 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
10343 | {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
10344 | |||
10345 | /* | ||
10346 | * Set up output mixers (0x0c - 0x0e) | ||
10347 | */ | ||
10348 | /* set vol=0 to output mixers */ | ||
10349 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
10350 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
10351 | |||
10352 | /* set up input amps for analog loopback */ | ||
10353 | /* Amp Indices: DAC = 0, mixer = 1 */ | ||
10354 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10355 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10356 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10357 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10358 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10359 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
10360 | |||
10361 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
10362 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
10363 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
10364 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
10365 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
10366 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
10367 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
10368 | |||
10369 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
10370 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
10371 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10372 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10373 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10374 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10375 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
10376 | |||
10377 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
10378 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
10379 | |||
10380 | /* FIXME: use matrix-type input source selection */ | ||
10381 | /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */ | ||
10382 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | ||
10383 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
10384 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
10385 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
10386 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
10387 | |||
10388 | /* set EAPD */ | ||
10389 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
10390 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2}, | ||
10391 | { } | ||
10392 | }; | ||
10393 | |||
10394 | /* add playback controls from the parsed DAC table */ | ||
10395 | static int alc269_auto_create_multi_out_ctls(struct alc_spec *spec, | ||
10396 | const struct auto_pin_cfg *cfg) | ||
10397 | { | ||
10398 | hda_nid_t nid; | ||
10399 | int err; | ||
10400 | |||
10401 | spec->multiout.num_dacs = 1; /* only use one dac */ | ||
10402 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
10403 | spec->multiout.dac_nids[0] = 2; | ||
10404 | |||
10405 | nid = cfg->line_out_pins[0]; | ||
10406 | if (nid) { | ||
10407 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10408 | "Front Playback Volume", | ||
10409 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT)); | ||
10410 | if (err < 0) | ||
10411 | return err; | ||
10412 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10413 | "Front Playback Switch", | ||
10414 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
10415 | if (err < 0) | ||
10416 | return err; | ||
10417 | } | ||
10418 | |||
10419 | nid = cfg->speaker_pins[0]; | ||
10420 | if (nid) { | ||
10421 | if (!cfg->line_out_pins[0]) { | ||
10422 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10423 | "Speaker Playback Volume", | ||
10424 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, | ||
10425 | HDA_OUTPUT)); | ||
10426 | if (err < 0) | ||
10427 | return err; | ||
10428 | } | ||
10429 | if (nid == 0x16) { | ||
10430 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10431 | "Speaker Playback Switch", | ||
10432 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | ||
10433 | HDA_OUTPUT)); | ||
10434 | if (err < 0) | ||
10435 | return err; | ||
10436 | } else { | ||
10437 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10438 | "Speaker Playback Switch", | ||
10439 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
10440 | HDA_OUTPUT)); | ||
10441 | if (err < 0) | ||
10442 | return err; | ||
10443 | } | ||
10444 | } | ||
10445 | nid = cfg->hp_pins[0]; | ||
10446 | if (nid) { | ||
10447 | /* spec->multiout.hp_nid = 2; */ | ||
10448 | if (!cfg->line_out_pins[0] && !cfg->speaker_pins[0]) { | ||
10449 | err = add_control(spec, ALC_CTL_WIDGET_VOL, | ||
10450 | "Headphone Playback Volume", | ||
10451 | HDA_COMPOSE_AMP_VAL(0x02, 3, 0, | ||
10452 | HDA_OUTPUT)); | ||
10453 | if (err < 0) | ||
10454 | return err; | ||
10455 | } | ||
10456 | if (nid == 0x16) { | ||
10457 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10458 | "Headphone Playback Switch", | ||
10459 | HDA_COMPOSE_AMP_VAL(nid, 2, 0, | ||
10460 | HDA_OUTPUT)); | ||
10461 | if (err < 0) | ||
10462 | return err; | ||
10463 | } else { | ||
10464 | err = add_control(spec, ALC_CTL_WIDGET_MUTE, | ||
10465 | "Headphone Playback Switch", | ||
10466 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
10467 | HDA_OUTPUT)); | ||
10468 | if (err < 0) | ||
10469 | return err; | ||
10470 | } | ||
10471 | } | ||
10472 | return 0; | ||
10473 | } | ||
10474 | |||
10475 | #define alc269_auto_create_analog_input_ctls \ | ||
10476 | alc880_auto_create_analog_input_ctls | ||
10477 | |||
10478 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10479 | #define alc269_loopbacks alc880_loopbacks | ||
10480 | #endif | ||
10481 | |||
10482 | /* pcm configuration: identiacal with ALC880 */ | ||
10483 | #define alc269_pcm_analog_playback alc880_pcm_analog_playback | ||
10484 | #define alc269_pcm_analog_capture alc880_pcm_analog_capture | ||
10485 | #define alc269_pcm_digital_playback alc880_pcm_digital_playback | ||
10486 | #define alc269_pcm_digital_capture alc880_pcm_digital_capture | ||
10487 | |||
10488 | /* | ||
10489 | * BIOS auto configuration | ||
10490 | */ | ||
10491 | static int alc269_parse_auto_config(struct hda_codec *codec) | ||
10492 | { | ||
10493 | struct alc_spec *spec = codec->spec; | ||
10494 | int err; | ||
10495 | static hda_nid_t alc269_ignore[] = { 0x1d, 0 }; | ||
10496 | |||
10497 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | ||
10498 | alc269_ignore); | ||
10499 | if (err < 0) | ||
10500 | return err; | ||
10501 | |||
10502 | err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
10503 | if (err < 0) | ||
10504 | return err; | ||
10505 | err = alc269_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
10506 | if (err < 0) | ||
10507 | return err; | ||
10508 | |||
10509 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
10510 | |||
10511 | if (spec->autocfg.dig_out_pin) | ||
10512 | spec->multiout.dig_out_nid = ALC269_DIGOUT_NID; | ||
10513 | |||
10514 | if (spec->kctl_alloc) | ||
10515 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
10516 | |||
10517 | spec->init_verbs[spec->num_init_verbs++] = alc269_init_verbs; | ||
10518 | spec->num_mux_defs = 1; | ||
10519 | spec->input_mux = &spec->private_imux; | ||
10520 | |||
10521 | err = alc_auto_add_mic_boost(codec); | ||
10522 | if (err < 0) | ||
10523 | return err; | ||
10524 | |||
10525 | return 1; | ||
10526 | } | ||
10527 | |||
10528 | #define alc269_auto_init_multi_out alc882_auto_init_multi_out | ||
10529 | #define alc269_auto_init_hp_out alc882_auto_init_hp_out | ||
10530 | #define alc269_auto_init_analog_input alc882_auto_init_analog_input | ||
10531 | |||
10532 | |||
10533 | /* init callback for auto-configuration model -- overriding the default init */ | ||
10534 | static void alc269_auto_init(struct hda_codec *codec) | ||
10535 | { | ||
10536 | alc269_auto_init_multi_out(codec); | ||
10537 | alc269_auto_init_hp_out(codec); | ||
10538 | alc269_auto_init_analog_input(codec); | ||
10539 | } | ||
10540 | |||
10541 | /* | ||
10542 | * configuration and preset | ||
10543 | */ | ||
10544 | static const char *alc269_models[ALC269_MODEL_LAST] = { | ||
10545 | [ALC269_BASIC] = "basic", | ||
10546 | }; | ||
10547 | |||
10548 | static struct snd_pci_quirk alc269_cfg_tbl[] = { | ||
10549 | {} | ||
10550 | }; | ||
10551 | |||
10552 | static struct alc_config_preset alc269_presets[] = { | ||
10553 | [ALC269_BASIC] = { | ||
10554 | .mixers = { alc269_base_mixer }, | ||
10555 | .init_verbs = { alc269_init_verbs }, | ||
10556 | .num_dacs = ARRAY_SIZE(alc269_dac_nids), | ||
10557 | .dac_nids = alc269_dac_nids, | ||
10558 | .hp_nid = 0x03, | ||
10559 | .num_channel_mode = ARRAY_SIZE(alc269_modes), | ||
10560 | .channel_mode = alc269_modes, | ||
10561 | .input_mux = &alc269_capture_source, | ||
10562 | }, | ||
10563 | }; | ||
10564 | |||
10565 | static int patch_alc269(struct hda_codec *codec) | ||
10566 | { | ||
10567 | struct alc_spec *spec; | ||
10568 | int board_config; | ||
10569 | int err; | ||
10570 | |||
10571 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
10572 | if (spec == NULL) | ||
10573 | return -ENOMEM; | ||
10574 | |||
10575 | codec->spec = spec; | ||
10576 | |||
10577 | board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, | ||
10578 | alc269_models, | ||
10579 | alc269_cfg_tbl); | ||
10580 | |||
10581 | if (board_config < 0) { | ||
10582 | printk(KERN_INFO "hda_codec: Unknown model for ALC269, " | ||
10583 | "trying auto-probe from BIOS...\n"); | ||
10584 | board_config = ALC269_AUTO; | ||
10585 | } | ||
10586 | |||
10587 | if (board_config == ALC269_AUTO) { | ||
10588 | /* automatic parse from the BIOS config */ | ||
10589 | err = alc269_parse_auto_config(codec); | ||
10590 | if (err < 0) { | ||
10591 | alc_free(codec); | ||
10592 | return err; | ||
10593 | } else if (!err) { | ||
10594 | printk(KERN_INFO | ||
10595 | "hda_codec: Cannot set up configuration " | ||
10596 | "from BIOS. Using base mode...\n"); | ||
10597 | board_config = ALC269_BASIC; | ||
10598 | } | ||
10599 | } | ||
10600 | |||
10601 | if (board_config != ALC269_AUTO) | ||
10602 | setup_preset(spec, &alc269_presets[board_config]); | ||
10603 | |||
10604 | spec->stream_name_analog = "ALC269 Analog"; | ||
10605 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | ||
10606 | spec->stream_analog_capture = &alc269_pcm_analog_capture; | ||
10607 | |||
10608 | spec->stream_name_digital = "ALC269 Digital"; | ||
10609 | spec->stream_digital_playback = &alc269_pcm_digital_playback; | ||
10610 | spec->stream_digital_capture = &alc269_pcm_digital_capture; | ||
10611 | |||
10612 | spec->adc_nids = alc269_adc_nids; | ||
10613 | spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids); | ||
10614 | spec->mixers[spec->num_mixers] = alc269_capture_mixer; | ||
10615 | spec->num_mixers++; | ||
10616 | |||
10617 | codec->patch_ops = alc_patch_ops; | ||
10618 | if (board_config == ALC269_AUTO) | ||
10619 | spec->init_hook = alc269_auto_init; | ||
10620 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
10621 | if (!spec->loopback.amplist) | ||
10622 | spec->loopback.amplist = alc269_loopbacks; | ||
10623 | #endif | ||
10624 | |||
10625 | return 0; | ||
10626 | } | ||
10627 | |||
10628 | /* | ||
9400 | * ALC861 channel source setting (2/6 channel selection for 3-stack) | 10629 | * ALC861 channel source setting (2/6 channel selection for 3-stack) |
9401 | */ | 10630 | */ |
9402 | 10631 | ||
@@ -10213,7 +11442,6 @@ static struct snd_kcontrol_new alc861_capture_mixer[] = { | |||
10213 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11442 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10214 | /* The multiple "Capture Source" controls confuse alsamixer | 11443 | /* The multiple "Capture Source" controls confuse alsamixer |
10215 | * So call somewhat different.. | 11444 | * So call somewhat different.. |
10216 | *FIXME: the controls appear in the "playback" view! | ||
10217 | */ | 11445 | */ |
10218 | /* .name = "Capture Source", */ | 11446 | /* .name = "Capture Source", */ |
10219 | .name = "Input Source", | 11447 | .name = "Input Source", |
@@ -10369,22 +11597,23 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = { | |||
10369 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), | 11597 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST), |
10370 | SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), | 11598 | SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP), |
10371 | SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), | 11599 | SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP), |
10372 | SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), | ||
10373 | SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), | ||
10374 | SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), | 11600 | SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS), |
11601 | SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP), | ||
10375 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), | 11602 | SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG), |
10376 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), | 11603 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA), |
10377 | /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) | 11604 | /* FIXME: the entry below breaks Toshiba A100 (model=auto works!) |
10378 | * Any other models that need this preset? | 11605 | * Any other models that need this preset? |
10379 | */ | 11606 | */ |
10380 | /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ | 11607 | /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */ |
10381 | SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), | 11608 | SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), |
10382 | SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), | 11609 | SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), |
10383 | SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), | 11610 | SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31), |
11611 | SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31), | ||
11612 | SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP), | ||
11613 | /* FIXME: the below seems conflict */ | ||
11614 | /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */ | ||
10384 | SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), | 11615 | SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST), |
10385 | SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), | 11616 | SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST), |
10386 | SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST), | ||
10387 | SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST), | ||
10388 | {} | 11617 | {} |
10389 | }; | 11618 | }; |
10390 | 11619 | ||
@@ -10543,6 +11772,8 @@ static int patch_alc861(struct hda_codec *codec) | |||
10543 | spec->stream_digital_playback = &alc861_pcm_digital_playback; | 11772 | spec->stream_digital_playback = &alc861_pcm_digital_playback; |
10544 | spec->stream_digital_capture = &alc861_pcm_digital_capture; | 11773 | spec->stream_digital_capture = &alc861_pcm_digital_capture; |
10545 | 11774 | ||
11775 | spec->vmaster_nid = 0x03; | ||
11776 | |||
10546 | codec->patch_ops = alc_patch_ops; | 11777 | codec->patch_ops = alc_patch_ops; |
10547 | if (board_config == ALC861_AUTO) | 11778 | if (board_config == ALC861_AUTO) |
10548 | spec->init_hook = alc861_auto_init; | 11779 | spec->init_hook = alc861_auto_init; |
@@ -10697,7 +11928,6 @@ static struct snd_kcontrol_new alc861vd_capture_mixer[] = { | |||
10697 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11928 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
10698 | /* The multiple "Capture Source" controls confuse alsamixer | 11929 | /* The multiple "Capture Source" controls confuse alsamixer |
10699 | * So call somewhat different.. | 11930 | * So call somewhat different.. |
10700 | *FIXME: the controls appear in the "playback" view! | ||
10701 | */ | 11931 | */ |
10702 | /* .name = "Capture Source", */ | 11932 | /* .name = "Capture Source", */ |
10703 | .name = "Input Source", | 11933 | .name = "Input Source", |
@@ -11102,21 +12332,20 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { | |||
11102 | }; | 12332 | }; |
11103 | 12333 | ||
11104 | static struct snd_pci_quirk alc861vd_cfg_tbl[] = { | 12334 | static struct snd_pci_quirk alc861vd_cfg_tbl[] = { |
12335 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | ||
12336 | SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), | ||
11105 | SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), | 12337 | SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST), |
11106 | SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), | 12338 | SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST), |
11107 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), | 12339 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG), |
11108 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), | 12340 | SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST), |
11109 | SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST), | 12341 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), |
11110 | |||
11111 | /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ | 12342 | /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/ |
11112 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), | 12343 | SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS), |
11113 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | ||
11114 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | ||
11115 | SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO), | ||
11116 | SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), | 12344 | SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO), |
11117 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), | 12345 | SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG), |
12346 | SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO), | ||
12347 | SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO), | ||
11118 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), | 12348 | SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG), |
11119 | SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP), | ||
11120 | {} | 12349 | {} |
11121 | }; | 12350 | }; |
11122 | 12351 | ||
@@ -11520,6 +12749,8 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
11520 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; | 12749 | spec->mixers[spec->num_mixers] = alc861vd_capture_mixer; |
11521 | spec->num_mixers++; | 12750 | spec->num_mixers++; |
11522 | 12751 | ||
12752 | spec->vmaster_nid = 0x02; | ||
12753 | |||
11523 | codec->patch_ops = alc_patch_ops; | 12754 | codec->patch_ops = alc_patch_ops; |
11524 | 12755 | ||
11525 | if (board_config == ALC861VD_AUTO) | 12756 | if (board_config == ALC861VD_AUTO) |
@@ -11699,18 +12930,6 @@ static struct snd_kcontrol_new alc662_base_mixer[] = { | |||
11699 | HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), | 12930 | HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT), |
11700 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), | 12931 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT), |
11701 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), | 12932 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT), |
11702 | |||
11703 | /* Capture mixer control */ | ||
11704 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11705 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11706 | { | ||
11707 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11708 | .name = "Capture Source", | ||
11709 | .count = 1, | ||
11710 | .info = alc_mux_enum_info, | ||
11711 | .get = alc_mux_enum_get, | ||
11712 | .put = alc_mux_enum_put, | ||
11713 | }, | ||
11714 | { } /* end */ | 12933 | { } /* end */ |
11715 | }; | 12934 | }; |
11716 | 12935 | ||
@@ -11728,17 +12947,6 @@ static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = { | |||
11728 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12947 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11729 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 12948 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
11730 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 12949 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
11731 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11732 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11733 | { | ||
11734 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11735 | /* .name = "Capture Source", */ | ||
11736 | .name = "Input Source", | ||
11737 | .count = 1, | ||
11738 | .info = alc662_mux_enum_info, | ||
11739 | .get = alc662_mux_enum_get, | ||
11740 | .put = alc662_mux_enum_put, | ||
11741 | }, | ||
11742 | { } /* end */ | 12950 | { } /* end */ |
11743 | }; | 12951 | }; |
11744 | 12952 | ||
@@ -11762,46 +12970,24 @@ static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = { | |||
11762 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12970 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11763 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 12971 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
11764 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 12972 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
11765 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11766 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11767 | { | ||
11768 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11769 | /* .name = "Capture Source", */ | ||
11770 | .name = "Input Source", | ||
11771 | .count = 1, | ||
11772 | .info = alc662_mux_enum_info, | ||
11773 | .get = alc662_mux_enum_get, | ||
11774 | .put = alc662_mux_enum_put, | ||
11775 | }, | ||
11776 | { } /* end */ | 12973 | { } /* end */ |
11777 | }; | 12974 | }; |
11778 | 12975 | ||
11779 | static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { | 12976 | static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { |
11780 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 12977 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
11781 | HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), | 12978 | HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT), |
11782 | HDA_CODEC_VOLUME("iSpeaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 12979 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
11783 | HDA_BIND_MUTE("iSpeaker Playback Switch", 0x03, 2, HDA_INPUT), | 12980 | HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT), |
11784 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 12981 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
11785 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 12982 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
11786 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 12983 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
11787 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | 12984 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), |
11788 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 12985 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
11789 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), | ||
11790 | HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), | ||
11791 | { | ||
11792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
11793 | /* .name = "Capture Source", */ | ||
11794 | .name = "Input Source", | ||
11795 | .count = 1, | ||
11796 | .info = alc662_mux_enum_info, | ||
11797 | .get = alc662_mux_enum_get, | ||
11798 | .put = alc662_mux_enum_put, | ||
11799 | }, | ||
11800 | { } /* end */ | 12986 | { } /* end */ |
11801 | }; | 12987 | }; |
11802 | 12988 | ||
11803 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | 12989 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { |
11804 | HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 12990 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
11805 | 12991 | ||
11806 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 12992 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
11807 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 12993 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
@@ -11816,6 +13002,24 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | |||
11816 | { } /* end */ | 13002 | { } /* end */ |
11817 | }; | 13003 | }; |
11818 | 13004 | ||
13005 | static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { | ||
13006 | HDA_CODEC_VOLUME("LineOut Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
13007 | HDA_CODEC_MUTE("LineOut Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
13008 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
13009 | HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), | ||
13010 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), | ||
13011 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), | ||
13012 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), | ||
13013 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), | ||
13014 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
13015 | HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), | ||
13016 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
13017 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
13018 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
13019 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
13020 | { } /* end */ | ||
13021 | }; | ||
13022 | |||
11819 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { | 13023 | static struct snd_kcontrol_new alc662_chmode_mixer[] = { |
11820 | { | 13024 | { |
11821 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13025 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -11901,6 +13105,13 @@ static struct hda_verb alc662_eeepc_sue_init_verbs[] = { | |||
11901 | {} | 13105 | {} |
11902 | }; | 13106 | }; |
11903 | 13107 | ||
13108 | /* Set Unsolicited Event*/ | ||
13109 | static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = { | ||
13110 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
13111 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, | ||
13112 | {} | ||
13113 | }; | ||
13114 | |||
11904 | /* | 13115 | /* |
11905 | * generic initialization of ADC, input mixers and output mixers | 13116 | * generic initialization of ADC, input mixers and output mixers |
11906 | */ | 13117 | */ |
@@ -11957,14 +13168,13 @@ static struct snd_kcontrol_new alc662_capture_mixer[] = { | |||
11957 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13168 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
11958 | /* The multiple "Capture Source" controls confuse alsamixer | 13169 | /* The multiple "Capture Source" controls confuse alsamixer |
11959 | * So call somewhat different.. | 13170 | * So call somewhat different.. |
11960 | * FIXME: the controls appear in the "playback" view! | ||
11961 | */ | 13171 | */ |
11962 | /* .name = "Capture Source", */ | 13172 | /* .name = "Capture Source", */ |
11963 | .name = "Input Source", | 13173 | .name = "Input Source", |
11964 | .count = 1, | 13174 | .count = 1, |
11965 | .info = alc882_mux_enum_info, | 13175 | .info = alc662_mux_enum_info, |
11966 | .get = alc882_mux_enum_get, | 13176 | .get = alc662_mux_enum_get, |
11967 | .put = alc882_mux_enum_put, | 13177 | .put = alc662_mux_enum_put, |
11968 | }, | 13178 | }, |
11969 | { } /* end */ | 13179 | { } /* end */ |
11970 | }; | 13180 | }; |
@@ -12037,6 +13247,40 @@ static void alc662_eeepc_inithook(struct hda_codec *codec) | |||
12037 | alc662_eeepc_mic_automute(codec); | 13247 | alc662_eeepc_mic_automute(codec); |
12038 | } | 13248 | } |
12039 | 13249 | ||
13250 | static void alc662_eeepc_ep20_automute(struct hda_codec *codec) | ||
13251 | { | ||
13252 | unsigned int mute; | ||
13253 | unsigned int present; | ||
13254 | |||
13255 | snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
13256 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
13257 | AC_VERB_GET_PIN_SENSE, 0); | ||
13258 | present = (present & 0x80000000) != 0; | ||
13259 | if (present) { | ||
13260 | /* mute internal speaker */ | ||
13261 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
13262 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
13263 | } else { | ||
13264 | /* unmute internal speaker if necessary */ | ||
13265 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); | ||
13266 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
13267 | HDA_AMP_MUTE, mute); | ||
13268 | } | ||
13269 | } | ||
13270 | |||
13271 | /* unsolicited event for HP jack sensing */ | ||
13272 | static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, | ||
13273 | unsigned int res) | ||
13274 | { | ||
13275 | if ((res >> 26) == ALC880_HP_EVENT) | ||
13276 | alc662_eeepc_ep20_automute(codec); | ||
13277 | } | ||
13278 | |||
13279 | static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) | ||
13280 | { | ||
13281 | alc662_eeepc_ep20_automute(codec); | ||
13282 | } | ||
13283 | |||
12040 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 13284 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
12041 | #define alc662_loopbacks alc880_loopbacks | 13285 | #define alc662_loopbacks alc880_loopbacks |
12042 | #endif | 13286 | #endif |
@@ -12057,12 +13301,15 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
12057 | [ALC662_3ST_6ch] = "3stack-6ch", | 13301 | [ALC662_3ST_6ch] = "3stack-6ch", |
12058 | [ALC662_5ST_DIG] = "6stack-dig", | 13302 | [ALC662_5ST_DIG] = "6stack-dig", |
12059 | [ALC662_LENOVO_101E] = "lenovo-101e", | 13303 | [ALC662_LENOVO_101E] = "lenovo-101e", |
13304 | [ALC662_ASUS_EEEPC_P701] = "eeepc-p701", | ||
13305 | [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20", | ||
12060 | [ALC662_AUTO] = "auto", | 13306 | [ALC662_AUTO] = "auto", |
12061 | }; | 13307 | }; |
12062 | 13308 | ||
12063 | static struct snd_pci_quirk alc662_cfg_tbl[] = { | 13309 | static struct snd_pci_quirk alc662_cfg_tbl[] = { |
12064 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | ||
12065 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), | 13310 | SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701), |
13311 | SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20), | ||
13312 | SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E), | ||
12066 | {} | 13313 | {} |
12067 | }; | 13314 | }; |
12068 | 13315 | ||
@@ -12149,6 +13396,21 @@ static struct alc_config_preset alc662_presets[] = { | |||
12149 | .unsol_event = alc662_eeepc_unsol_event, | 13396 | .unsol_event = alc662_eeepc_unsol_event, |
12150 | .init_hook = alc662_eeepc_inithook, | 13397 | .init_hook = alc662_eeepc_inithook, |
12151 | }, | 13398 | }, |
13399 | [ALC662_ASUS_EEEPC_EP20] = { | ||
13400 | .mixers = { alc662_eeepc_ep20_mixer, alc662_capture_mixer, | ||
13401 | alc662_chmode_mixer }, | ||
13402 | .init_verbs = { alc662_init_verbs, | ||
13403 | alc662_eeepc_ep20_sue_init_verbs }, | ||
13404 | .num_dacs = ARRAY_SIZE(alc662_dac_nids), | ||
13405 | .dac_nids = alc662_dac_nids, | ||
13406 | .num_adc_nids = ARRAY_SIZE(alc662_adc_nids), | ||
13407 | .adc_nids = alc662_adc_nids, | ||
13408 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), | ||
13409 | .channel_mode = alc662_3ST_6ch_modes, | ||
13410 | .input_mux = &alc662_lenovo_101e_capture_source, | ||
13411 | .unsol_event = alc662_eeepc_ep20_unsol_event, | ||
13412 | .init_hook = alc662_eeepc_ep20_inithook, | ||
13413 | }, | ||
12152 | 13414 | ||
12153 | }; | 13415 | }; |
12154 | 13416 | ||
@@ -12308,6 +13570,7 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) | |||
12308 | struct alc_spec *spec = codec->spec; | 13570 | struct alc_spec *spec = codec->spec; |
12309 | int i; | 13571 | int i; |
12310 | 13572 | ||
13573 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
12311 | for (i = 0; i <= HDA_SIDE; i++) { | 13574 | for (i = 0; i <= HDA_SIDE; i++) { |
12312 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 13575 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
12313 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 13576 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -12458,6 +13721,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
12458 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); | 13721 | spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids); |
12459 | } | 13722 | } |
12460 | 13723 | ||
13724 | spec->vmaster_nid = 0x02; | ||
13725 | |||
12461 | codec->patch_ops = alc_patch_ops; | 13726 | codec->patch_ops = alc_patch_ops; |
12462 | if (board_config == ALC662_AUTO) | 13727 | if (board_config == ALC662_AUTO) |
12463 | spec->init_hook = alc662_auto_init; | 13728 | spec->init_hook = alc662_auto_init; |
@@ -12475,7 +13740,9 @@ static int patch_alc662(struct hda_codec *codec) | |||
12475 | struct hda_codec_preset snd_hda_preset_realtek[] = { | 13740 | struct hda_codec_preset snd_hda_preset_realtek[] = { |
12476 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, | 13741 | { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, |
12477 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, | 13742 | { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, |
13743 | { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, | ||
12478 | { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, | 13744 | { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, |
13745 | { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, | ||
12479 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", | 13746 | { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", |
12480 | .patch = patch_alc861 }, | 13747 | .patch = patch_alc861 }, |
12481 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, | 13748 | { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, |
@@ -12490,5 +13757,6 @@ struct hda_codec_preset snd_hda_preset_realtek[] = { | |||
12490 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, | 13757 | { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, |
12491 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, | 13758 | { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, |
12492 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, | 13759 | { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, |
13760 | { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, | ||
12493 | {} /* terminator */ | 13761 | {} /* terminator */ |
12494 | }; | 13762 | }; |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 2a4b9609aa5c..d22f5a6b850f 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
@@ -287,7 +286,6 @@ static int patch_si3054(struct hda_codec *codec) | |||
287 | struct hda_codec_preset snd_hda_preset_si3054[] = { | 286 | struct hda_codec_preset snd_hda_preset_si3054[] = { |
288 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, | 287 | { .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 }, |
289 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, | 288 | { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 }, |
290 | { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 }, | ||
291 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, | 289 | { .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 }, |
292 | { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, | 290 | { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 }, |
293 | { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, | 291 | { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 }, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index f9b2c435a130..caf48edaa921 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -24,7 +24,6 @@ | |||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
@@ -35,7 +34,8 @@ | |||
35 | #include "hda_local.h" | 34 | #include "hda_local.h" |
36 | 35 | ||
37 | #define NUM_CONTROL_ALLOC 32 | 36 | #define NUM_CONTROL_ALLOC 32 |
38 | #define STAC_HP_EVENT 0x37 | 37 | #define STAC_PWR_EVENT 0x20 |
38 | #define STAC_HP_EVENT 0x30 | ||
39 | 39 | ||
40 | enum { | 40 | enum { |
41 | STAC_REF, | 41 | STAC_REF, |
@@ -62,6 +62,16 @@ enum { | |||
62 | }; | 62 | }; |
63 | 63 | ||
64 | enum { | 64 | enum { |
65 | STAC_92HD73XX_REF, | ||
66 | STAC_92HD73XX_MODELS | ||
67 | }; | ||
68 | |||
69 | enum { | ||
70 | STAC_92HD71BXX_REF, | ||
71 | STAC_92HD71BXX_MODELS | ||
72 | }; | ||
73 | |||
74 | enum { | ||
65 | STAC_925x_REF, | 75 | STAC_925x_REF, |
66 | STAC_M2_2, | 76 | STAC_M2_2, |
67 | STAC_MA6, | 77 | STAC_MA6, |
@@ -97,6 +107,7 @@ enum { | |||
97 | STAC_D965_3ST, | 107 | STAC_D965_3ST, |
98 | STAC_D965_5ST, | 108 | STAC_D965_5ST, |
99 | STAC_DELL_3ST, | 109 | STAC_DELL_3ST, |
110 | STAC_DELL_BIOS, | ||
100 | STAC_927X_MODELS | 111 | STAC_927X_MODELS |
101 | }; | 112 | }; |
102 | 113 | ||
@@ -110,12 +121,24 @@ struct sigmatel_spec { | |||
110 | unsigned int mic_switch: 1; | 121 | unsigned int mic_switch: 1; |
111 | unsigned int alt_switch: 1; | 122 | unsigned int alt_switch: 1; |
112 | unsigned int hp_detect: 1; | 123 | unsigned int hp_detect: 1; |
113 | unsigned int gpio_mute: 1; | ||
114 | unsigned int no_vol_knob :1; | ||
115 | 124 | ||
116 | unsigned int gpio_mask, gpio_data; | 125 | /* gpio lines */ |
126 | unsigned int gpio_mask; | ||
127 | unsigned int gpio_dir; | ||
128 | unsigned int gpio_data; | ||
129 | unsigned int gpio_mute; | ||
130 | |||
131 | /* analog loopback */ | ||
132 | unsigned char aloopback_mask; | ||
133 | unsigned char aloopback_shift; | ||
134 | |||
135 | /* power management */ | ||
136 | unsigned int num_pwrs; | ||
137 | hda_nid_t *pwr_nids; | ||
117 | 138 | ||
118 | /* playback */ | 139 | /* playback */ |
140 | struct hda_input_mux *mono_mux; | ||
141 | unsigned int cur_mmux; | ||
119 | struct hda_multi_out multiout; | 142 | struct hda_multi_out multiout; |
120 | hda_nid_t dac_nids[5]; | 143 | hda_nid_t dac_nids[5]; |
121 | 144 | ||
@@ -126,8 +149,10 @@ struct sigmatel_spec { | |||
126 | unsigned int num_muxes; | 149 | unsigned int num_muxes; |
127 | hda_nid_t *dmic_nids; | 150 | hda_nid_t *dmic_nids; |
128 | unsigned int num_dmics; | 151 | unsigned int num_dmics; |
129 | hda_nid_t dmux_nid; | 152 | hda_nid_t *dmux_nids; |
153 | unsigned int num_dmuxes; | ||
130 | hda_nid_t dig_in_nid; | 154 | hda_nid_t dig_in_nid; |
155 | hda_nid_t mono_nid; | ||
131 | 156 | ||
132 | /* pin widgets */ | 157 | /* pin widgets */ |
133 | hda_nid_t *pin_nids; | 158 | hda_nid_t *pin_nids; |
@@ -141,7 +166,7 @@ struct sigmatel_spec { | |||
141 | 166 | ||
142 | /* capture source */ | 167 | /* capture source */ |
143 | struct hda_input_mux *dinput_mux; | 168 | struct hda_input_mux *dinput_mux; |
144 | unsigned int cur_dmux; | 169 | unsigned int cur_dmux[2]; |
145 | struct hda_input_mux *input_mux; | 170 | struct hda_input_mux *input_mux; |
146 | unsigned int cur_mux[3]; | 171 | unsigned int cur_mux[3]; |
147 | 172 | ||
@@ -158,6 +183,10 @@ struct sigmatel_spec { | |||
158 | struct snd_kcontrol_new *kctl_alloc; | 183 | struct snd_kcontrol_new *kctl_alloc; |
159 | struct hda_input_mux private_dimux; | 184 | struct hda_input_mux private_dimux; |
160 | struct hda_input_mux private_imux; | 185 | struct hda_input_mux private_imux; |
186 | struct hda_input_mux private_mono_mux; | ||
187 | |||
188 | /* virtual master */ | ||
189 | unsigned int vmaster_tlv[4]; | ||
161 | }; | 190 | }; |
162 | 191 | ||
163 | static hda_nid_t stac9200_adc_nids[1] = { | 192 | static hda_nid_t stac9200_adc_nids[1] = { |
@@ -172,6 +201,58 @@ static hda_nid_t stac9200_dac_nids[1] = { | |||
172 | 0x02, | 201 | 0x02, |
173 | }; | 202 | }; |
174 | 203 | ||
204 | static hda_nid_t stac92hd73xx_pwr_nids[8] = { | ||
205 | 0x0a, 0x0b, 0x0c, 0xd, 0x0e, | ||
206 | 0x0f, 0x10, 0x11 | ||
207 | }; | ||
208 | |||
209 | static hda_nid_t stac92hd73xx_adc_nids[2] = { | ||
210 | 0x1a, 0x1b | ||
211 | }; | ||
212 | |||
213 | #define STAC92HD73XX_NUM_DMICS 2 | ||
214 | static hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { | ||
215 | 0x13, 0x14, 0 | ||
216 | }; | ||
217 | |||
218 | #define STAC92HD73_DAC_COUNT 5 | ||
219 | static hda_nid_t stac92hd73xx_dac_nids[STAC92HD73_DAC_COUNT] = { | ||
220 | 0x15, 0x16, 0x17, 0x18, 0x19, | ||
221 | }; | ||
222 | |||
223 | static hda_nid_t stac92hd73xx_mux_nids[4] = { | ||
224 | 0x28, 0x29, 0x2a, 0x2b, | ||
225 | }; | ||
226 | |||
227 | static hda_nid_t stac92hd73xx_dmux_nids[2] = { | ||
228 | 0x20, 0x21, | ||
229 | }; | ||
230 | |||
231 | static hda_nid_t stac92hd71bxx_pwr_nids[3] = { | ||
232 | 0x0a, 0x0d, 0x0f | ||
233 | }; | ||
234 | |||
235 | static hda_nid_t stac92hd71bxx_adc_nids[2] = { | ||
236 | 0x12, 0x13, | ||
237 | }; | ||
238 | |||
239 | static hda_nid_t stac92hd71bxx_mux_nids[2] = { | ||
240 | 0x1a, 0x1b | ||
241 | }; | ||
242 | |||
243 | static hda_nid_t stac92hd71bxx_dmux_nids[1] = { | ||
244 | 0x1c, | ||
245 | }; | ||
246 | |||
247 | static hda_nid_t stac92hd71bxx_dac_nids[2] = { | ||
248 | 0x10, /*0x11, */ | ||
249 | }; | ||
250 | |||
251 | #define STAC92HD71BXX_NUM_DMICS 2 | ||
252 | static hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { | ||
253 | 0x18, 0x19, 0 | ||
254 | }; | ||
255 | |||
175 | static hda_nid_t stac925x_adc_nids[1] = { | 256 | static hda_nid_t stac925x_adc_nids[1] = { |
176 | 0x03, | 257 | 0x03, |
177 | }; | 258 | }; |
@@ -189,6 +270,10 @@ static hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { | |||
189 | 0x15, 0 | 270 | 0x15, 0 |
190 | }; | 271 | }; |
191 | 272 | ||
273 | static hda_nid_t stac925x_dmux_nids[1] = { | ||
274 | 0x14, | ||
275 | }; | ||
276 | |||
192 | static hda_nid_t stac922x_adc_nids[2] = { | 277 | static hda_nid_t stac922x_adc_nids[2] = { |
193 | 0x06, 0x07, | 278 | 0x06, 0x07, |
194 | }; | 279 | }; |
@@ -205,6 +290,15 @@ static hda_nid_t stac927x_mux_nids[3] = { | |||
205 | 0x15, 0x16, 0x17 | 290 | 0x15, 0x16, 0x17 |
206 | }; | 291 | }; |
207 | 292 | ||
293 | static hda_nid_t stac927x_dmux_nids[1] = { | ||
294 | 0x1b, | ||
295 | }; | ||
296 | |||
297 | #define STAC927X_NUM_DMICS 2 | ||
298 | static hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { | ||
299 | 0x13, 0x14, 0 | ||
300 | }; | ||
301 | |||
208 | static hda_nid_t stac9205_adc_nids[2] = { | 302 | static hda_nid_t stac9205_adc_nids[2] = { |
209 | 0x12, 0x13 | 303 | 0x12, 0x13 |
210 | }; | 304 | }; |
@@ -213,6 +307,10 @@ static hda_nid_t stac9205_mux_nids[2] = { | |||
213 | 0x19, 0x1a | 307 | 0x19, 0x1a |
214 | }; | 308 | }; |
215 | 309 | ||
310 | static hda_nid_t stac9205_dmux_nids[1] = { | ||
311 | 0x1d, | ||
312 | }; | ||
313 | |||
216 | #define STAC9205_NUM_DMICS 2 | 314 | #define STAC9205_NUM_DMICS 2 |
217 | static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { | 315 | static hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { |
218 | 0x17, 0x18, 0 | 316 | 0x17, 0x18, 0 |
@@ -233,6 +331,17 @@ static hda_nid_t stac922x_pin_nids[10] = { | |||
233 | 0x0f, 0x10, 0x11, 0x15, 0x1b, | 331 | 0x0f, 0x10, 0x11, 0x15, 0x1b, |
234 | }; | 332 | }; |
235 | 333 | ||
334 | static hda_nid_t stac92hd73xx_pin_nids[12] = { | ||
335 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
336 | 0x0f, 0x10, 0x11, 0x12, 0x13, | ||
337 | 0x14, 0x22 | ||
338 | }; | ||
339 | |||
340 | static hda_nid_t stac92hd71bxx_pin_nids[10] = { | ||
341 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | ||
342 | 0x0f, 0x14, 0x18, 0x19, 0x1e, | ||
343 | }; | ||
344 | |||
236 | static hda_nid_t stac927x_pin_nids[14] = { | 345 | static hda_nid_t stac927x_pin_nids[14] = { |
237 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, | 346 | 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, |
238 | 0x0f, 0x10, 0x11, 0x12, 0x13, | 347 | 0x0f, 0x10, 0x11, 0x12, 0x13, |
@@ -258,8 +367,9 @@ static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, | |||
258 | { | 367 | { |
259 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 368 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
260 | struct sigmatel_spec *spec = codec->spec; | 369 | struct sigmatel_spec *spec = codec->spec; |
370 | unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
261 | 371 | ||
262 | ucontrol->value.enumerated.item[0] = spec->cur_dmux; | 372 | ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx]; |
263 | return 0; | 373 | return 0; |
264 | } | 374 | } |
265 | 375 | ||
@@ -268,9 +378,10 @@ static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, | |||
268 | { | 378 | { |
269 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 379 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
270 | struct sigmatel_spec *spec = codec->spec; | 380 | struct sigmatel_spec *spec = codec->spec; |
381 | unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
271 | 382 | ||
272 | return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, | 383 | return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, |
273 | spec->dmux_nid, &spec->cur_dmux); | 384 | spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); |
274 | } | 385 | } |
275 | 386 | ||
276 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 387 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
@@ -300,15 +411,45 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
300 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); | 411 | spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); |
301 | } | 412 | } |
302 | 413 | ||
414 | static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
415 | struct snd_ctl_elem_info *uinfo) | ||
416 | { | ||
417 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
418 | struct sigmatel_spec *spec = codec->spec; | ||
419 | return snd_hda_input_mux_info(spec->mono_mux, uinfo); | ||
420 | } | ||
421 | |||
422 | static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
423 | struct snd_ctl_elem_value *ucontrol) | ||
424 | { | ||
425 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
426 | struct sigmatel_spec *spec = codec->spec; | ||
427 | |||
428 | ucontrol->value.enumerated.item[0] = spec->cur_mmux; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
436 | struct sigmatel_spec *spec = codec->spec; | ||
437 | |||
438 | return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol, | ||
439 | spec->mono_nid, &spec->cur_mmux); | ||
440 | } | ||
441 | |||
303 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info | 442 | #define stac92xx_aloopback_info snd_ctl_boolean_mono_info |
304 | 443 | ||
305 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, | 444 | static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, |
306 | struct snd_ctl_elem_value *ucontrol) | 445 | struct snd_ctl_elem_value *ucontrol) |
307 | { | 446 | { |
308 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 447 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
448 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
309 | struct sigmatel_spec *spec = codec->spec; | 449 | struct sigmatel_spec *spec = codec->spec; |
310 | 450 | ||
311 | ucontrol->value.integer.value[0] = spec->aloopback; | 451 | ucontrol->value.integer.value[0] = !!(spec->aloopback & |
452 | (spec->aloopback_mask << idx)); | ||
312 | return 0; | 453 | return 0; |
313 | } | 454 | } |
314 | 455 | ||
@@ -317,23 +458,33 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, | |||
317 | { | 458 | { |
318 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 459 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
319 | struct sigmatel_spec *spec = codec->spec; | 460 | struct sigmatel_spec *spec = codec->spec; |
461 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
320 | unsigned int dac_mode; | 462 | unsigned int dac_mode; |
463 | unsigned int val, idx_val; | ||
321 | 464 | ||
322 | if (spec->aloopback == ucontrol->value.integer.value[0]) | 465 | idx_val = spec->aloopback_mask << idx; |
466 | if (ucontrol->value.integer.value[0]) | ||
467 | val = spec->aloopback | idx_val; | ||
468 | else | ||
469 | val = spec->aloopback & ~idx_val; | ||
470 | if (spec->aloopback == val) | ||
323 | return 0; | 471 | return 0; |
324 | 472 | ||
325 | spec->aloopback = ucontrol->value.integer.value[0]; | 473 | spec->aloopback = val; |
326 | |||
327 | 474 | ||
475 | /* Only return the bits defined by the shift value of the | ||
476 | * first two bytes of the mask | ||
477 | */ | ||
328 | dac_mode = snd_hda_codec_read(codec, codec->afg, 0, | 478 | dac_mode = snd_hda_codec_read(codec, codec->afg, 0, |
329 | kcontrol->private_value & 0xFFFF, 0x0); | 479 | kcontrol->private_value & 0xFFFF, 0x0); |
480 | dac_mode >>= spec->aloopback_shift; | ||
330 | 481 | ||
331 | if (spec->aloopback) { | 482 | if (spec->aloopback & idx_val) { |
332 | snd_hda_power_up(codec); | 483 | snd_hda_power_up(codec); |
333 | dac_mode |= 0x40; | 484 | dac_mode |= idx_val; |
334 | } else { | 485 | } else { |
335 | snd_hda_power_down(codec); | 486 | snd_hda_power_down(codec); |
336 | dac_mode &= ~0x40; | 487 | dac_mode &= ~idx_val; |
337 | } | 488 | } |
338 | 489 | ||
339 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 490 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
@@ -342,42 +493,6 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, | |||
342 | return 1; | 493 | return 1; |
343 | } | 494 | } |
344 | 495 | ||
345 | static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, | ||
346 | struct snd_ctl_elem_info *uinfo) | ||
347 | { | ||
348 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
349 | uinfo->count = 1; | ||
350 | uinfo->value.integer.min = 0; | ||
351 | uinfo->value.integer.max = 127; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, | ||
356 | struct snd_ctl_elem_value *ucontrol) | ||
357 | { | ||
358 | ucontrol->value.integer.value[0] = kcontrol->private_value & 0xff; | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, | ||
363 | struct snd_ctl_elem_value *ucontrol) | ||
364 | { | ||
365 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
366 | unsigned int val = kcontrol->private_value & 0xff; | ||
367 | |||
368 | if (val == ucontrol->value.integer.value[0]) | ||
369 | return 0; | ||
370 | |||
371 | val = ucontrol->value.integer.value[0]; | ||
372 | kcontrol->private_value &= ~0xff; | ||
373 | kcontrol->private_value |= val; | ||
374 | |||
375 | snd_hda_codec_write_cache(codec, kcontrol->private_value >> 16, 0, | ||
376 | AC_VERB_SET_VOLUME_KNOB_CONTROL, val | 0x80); | ||
377 | return 1; | ||
378 | } | ||
379 | |||
380 | |||
381 | static struct hda_verb stac9200_core_init[] = { | 496 | static struct hda_verb stac9200_core_init[] = { |
382 | /* set dac0mux for dac converter */ | 497 | /* set dac0mux for dac converter */ |
383 | { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, | 498 | { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -391,6 +506,107 @@ static struct hda_verb stac9200_eapd_init[] = { | |||
391 | {} | 506 | {} |
392 | }; | 507 | }; |
393 | 508 | ||
509 | static struct hda_verb stac92hd73xx_6ch_core_init[] = { | ||
510 | /* set master volume and direct control */ | ||
511 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
512 | /* setup audio connections */ | ||
513 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
514 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
515 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
516 | /* setup adcs to point to mixer */ | ||
517 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
518 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
519 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
520 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
521 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
522 | /* setup import muxs */ | ||
523 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
524 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
525 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
526 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
527 | {} | ||
528 | }; | ||
529 | |||
530 | static struct hda_verb stac92hd73xx_8ch_core_init[] = { | ||
531 | /* set master volume and direct control */ | ||
532 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
533 | /* setup audio connections */ | ||
534 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
535 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
536 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
537 | /* connect hp ports to dac3 */ | ||
538 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
539 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
540 | /* setup adcs to point to mixer */ | ||
541 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
542 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
543 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
544 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
545 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
546 | /* setup import muxs */ | ||
547 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
548 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
549 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
550 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
551 | {} | ||
552 | }; | ||
553 | |||
554 | static struct hda_verb stac92hd73xx_10ch_core_init[] = { | ||
555 | /* set master volume and direct control */ | ||
556 | { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
557 | /* setup audio connections */ | ||
558 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, | ||
559 | { 0x10, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
560 | { 0x11, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
561 | /* dac3 is connected to import3 mux */ | ||
562 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb07f}, | ||
563 | /* connect hp ports to dac4 */ | ||
564 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x04}, | ||
565 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x04}, | ||
566 | /* setup adcs to point to mixer */ | ||
567 | { 0x20, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
568 | { 0x21, AC_VERB_SET_CONNECT_SEL, 0x0b}, | ||
569 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
570 | { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
571 | { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
572 | /* setup import muxs */ | ||
573 | { 0x28, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
574 | { 0x29, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
575 | { 0x2a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
576 | { 0x2b, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
577 | {} | ||
578 | }; | ||
579 | |||
580 | static struct hda_verb stac92hd71bxx_core_init[] = { | ||
581 | /* set master volume and direct control */ | ||
582 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
583 | /* connect headphone jack to dac1 */ | ||
584 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
585 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
586 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | ||
587 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
588 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
589 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
590 | }; | ||
591 | |||
592 | static struct hda_verb stac92hd71bxx_analog_core_init[] = { | ||
593 | /* set master volume and direct control */ | ||
594 | { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, | ||
595 | /* connect headphone jack to dac1 */ | ||
596 | { 0x0a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
597 | /* connect ports 0d and 0f to audio mixer */ | ||
598 | { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
599 | { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
600 | { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Speaker */ | ||
601 | /* unmute dac0 input in audio mixer */ | ||
602 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f}, | ||
603 | /* unmute right and left channels for nodes 0x0a, 0xd, 0x0f */ | ||
604 | { 0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
605 | { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
606 | { 0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
607 | {} | ||
608 | }; | ||
609 | |||
394 | static struct hda_verb stac925x_core_init[] = { | 610 | static struct hda_verb stac925x_core_init[] = { |
395 | /* set dac0mux for dac converter */ | 611 | /* set dac0mux for dac converter */ |
396 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, | 612 | { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -425,6 +641,16 @@ static struct hda_verb stac9205_core_init[] = { | |||
425 | {} | 641 | {} |
426 | }; | 642 | }; |
427 | 643 | ||
644 | #define STAC_MONO_MUX \ | ||
645 | { \ | ||
646 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
647 | .name = "Mono Mux", \ | ||
648 | .count = 1, \ | ||
649 | .info = stac92xx_mono_mux_enum_info, \ | ||
650 | .get = stac92xx_mono_mux_enum_get, \ | ||
651 | .put = stac92xx_mono_mux_enum_put, \ | ||
652 | } | ||
653 | |||
428 | #define STAC_INPUT_SOURCE(cnt) \ | 654 | #define STAC_INPUT_SOURCE(cnt) \ |
429 | { \ | 655 | { \ |
430 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 656 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
@@ -435,29 +661,17 @@ static struct hda_verb stac9205_core_init[] = { | |||
435 | .put = stac92xx_mux_enum_put, \ | 661 | .put = stac92xx_mux_enum_put, \ |
436 | } | 662 | } |
437 | 663 | ||
438 | #define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ | 664 | #define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ |
439 | { \ | 665 | { \ |
440 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 666 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
441 | .name = "Analog Loopback", \ | 667 | .name = "Analog Loopback", \ |
442 | .count = 1, \ | 668 | .count = cnt, \ |
443 | .info = stac92xx_aloopback_info, \ | 669 | .info = stac92xx_aloopback_info, \ |
444 | .get = stac92xx_aloopback_get, \ | 670 | .get = stac92xx_aloopback_get, \ |
445 | .put = stac92xx_aloopback_put, \ | 671 | .put = stac92xx_aloopback_put, \ |
446 | .private_value = verb_read | (verb_write << 16), \ | 672 | .private_value = verb_read | (verb_write << 16), \ |
447 | } | 673 | } |
448 | 674 | ||
449 | #define STAC_VOLKNOB(knob_nid) \ | ||
450 | { \ | ||
451 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
452 | .name = "Master Playback Volume", \ | ||
453 | .count = 1, \ | ||
454 | .info = stac92xx_volknob_info, \ | ||
455 | .get = stac92xx_volknob_get, \ | ||
456 | .put = stac92xx_volknob_put, \ | ||
457 | .private_value = 127 | (knob_nid << 16), \ | ||
458 | } | ||
459 | |||
460 | |||
461 | static struct snd_kcontrol_new stac9200_mixer[] = { | 675 | static struct snd_kcontrol_new stac9200_mixer[] = { |
462 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 676 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
463 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 677 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
@@ -468,6 +682,114 @@ static struct snd_kcontrol_new stac9200_mixer[] = { | |||
468 | { } /* end */ | 682 | { } /* end */ |
469 | }; | 683 | }; |
470 | 684 | ||
685 | static struct snd_kcontrol_new stac92hd73xx_6ch_mixer[] = { | ||
686 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), | ||
687 | |||
688 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
689 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
690 | |||
691 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
692 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
693 | |||
694 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
695 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
696 | |||
697 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
698 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
699 | |||
700 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
701 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
702 | |||
703 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
704 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
705 | |||
706 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
707 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
708 | { } /* end */ | ||
709 | }; | ||
710 | |||
711 | static struct snd_kcontrol_new stac92hd73xx_8ch_mixer[] = { | ||
712 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), | ||
713 | |||
714 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
715 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
716 | |||
717 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
718 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
719 | |||
720 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
721 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
722 | |||
723 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
724 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
725 | |||
726 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
727 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
728 | |||
729 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
730 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
731 | |||
732 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
733 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
734 | { } /* end */ | ||
735 | }; | ||
736 | |||
737 | static struct snd_kcontrol_new stac92hd73xx_10ch_mixer[] = { | ||
738 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), | ||
739 | |||
740 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
741 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x20, 0x0, HDA_OUTPUT), | ||
742 | |||
743 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
744 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x21, 0x0, HDA_OUTPUT), | ||
745 | |||
746 | HDA_CODEC_VOLUME("Front Mic Mixer Capture Volume", 0x1d, 0, HDA_INPUT), | ||
747 | HDA_CODEC_MUTE("Front Mic Mixer Capture Switch", 0x1d, 0, HDA_INPUT), | ||
748 | |||
749 | HDA_CODEC_VOLUME("Mic Mixer Capture Volume", 0x1d, 0x1, HDA_INPUT), | ||
750 | HDA_CODEC_MUTE("Mic Mixer Capture Switch", 0x1d, 0x1, HDA_INPUT), | ||
751 | |||
752 | HDA_CODEC_VOLUME("Line In Mixer Capture Volume", 0x1d, 0x2, HDA_INPUT), | ||
753 | HDA_CODEC_MUTE("Line In Mixer Capture Switch", 0x1d, 0x2, HDA_INPUT), | ||
754 | |||
755 | HDA_CODEC_VOLUME("DAC Mixer Capture Volume", 0x1d, 0x3, HDA_INPUT), | ||
756 | HDA_CODEC_MUTE("DAC Mixer Capture Switch", 0x1d, 0x3, HDA_INPUT), | ||
757 | |||
758 | HDA_CODEC_VOLUME("CD Mixer Capture Volume", 0x1d, 0x4, HDA_INPUT), | ||
759 | HDA_CODEC_MUTE("CD Mixer Capture Switch", 0x1d, 0x4, HDA_INPUT), | ||
760 | { } /* end */ | ||
761 | }; | ||
762 | |||
763 | static struct snd_kcontrol_new stac92hd71bxx_analog_mixer[] = { | ||
764 | STAC_INPUT_SOURCE(2), | ||
765 | |||
766 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
767 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
768 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), | ||
769 | |||
770 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
771 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
772 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | ||
773 | |||
774 | HDA_CODEC_MUTE("Analog Loopback 1", 0x17, 0x3, HDA_INPUT), | ||
775 | HDA_CODEC_MUTE("Analog Loopback 2", 0x17, 0x4, HDA_INPUT), | ||
776 | { } /* end */ | ||
777 | }; | ||
778 | |||
779 | static struct snd_kcontrol_new stac92hd71bxx_mixer[] = { | ||
780 | STAC_INPUT_SOURCE(2), | ||
781 | STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2), | ||
782 | |||
783 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
784 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1c, 0x0, HDA_OUTPUT), | ||
785 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x0, 0x1a, 0x0, HDA_OUTPUT), | ||
786 | |||
787 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
788 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1d, 0x0, HDA_OUTPUT), | ||
789 | HDA_CODEC_VOLUME_IDX("Capture Mux Volume", 0x1, 0x1b, 0x0, HDA_OUTPUT), | ||
790 | { } /* end */ | ||
791 | }; | ||
792 | |||
471 | static struct snd_kcontrol_new stac925x_mixer[] = { | 793 | static struct snd_kcontrol_new stac925x_mixer[] = { |
472 | STAC_INPUT_SOURCE(1), | 794 | STAC_INPUT_SOURCE(1), |
473 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), | 795 | HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), |
@@ -477,17 +799,8 @@ static struct snd_kcontrol_new stac925x_mixer[] = { | |||
477 | }; | 799 | }; |
478 | 800 | ||
479 | static struct snd_kcontrol_new stac9205_mixer[] = { | 801 | static struct snd_kcontrol_new stac9205_mixer[] = { |
480 | { | ||
481 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
482 | .name = "Digital Input Source", | ||
483 | .count = 1, | ||
484 | .info = stac92xx_dmux_enum_info, | ||
485 | .get = stac92xx_dmux_enum_get, | ||
486 | .put = stac92xx_dmux_enum_put, | ||
487 | }, | ||
488 | STAC_INPUT_SOURCE(2), | 802 | STAC_INPUT_SOURCE(2), |
489 | STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), | 803 | STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), |
490 | STAC_VOLKNOB(0x24), | ||
491 | 804 | ||
492 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), | 805 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), |
493 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), | 806 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), |
@@ -503,7 +816,6 @@ static struct snd_kcontrol_new stac9205_mixer[] = { | |||
503 | /* This needs to be generated dynamically based on sequence */ | 816 | /* This needs to be generated dynamically based on sequence */ |
504 | static struct snd_kcontrol_new stac922x_mixer[] = { | 817 | static struct snd_kcontrol_new stac922x_mixer[] = { |
505 | STAC_INPUT_SOURCE(2), | 818 | STAC_INPUT_SOURCE(2), |
506 | STAC_VOLKNOB(0x16), | ||
507 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), | 819 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), |
508 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), | 820 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), |
509 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), | 821 | HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), |
@@ -517,8 +829,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { | |||
517 | 829 | ||
518 | static struct snd_kcontrol_new stac927x_mixer[] = { | 830 | static struct snd_kcontrol_new stac927x_mixer[] = { |
519 | STAC_INPUT_SOURCE(3), | 831 | STAC_INPUT_SOURCE(3), |
520 | STAC_VOLKNOB(0x24), | 832 | STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), |
521 | STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), | ||
522 | 833 | ||
523 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), | 834 | HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), |
524 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), | 835 | HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), |
@@ -534,6 +845,44 @@ static struct snd_kcontrol_new stac927x_mixer[] = { | |||
534 | { } /* end */ | 845 | { } /* end */ |
535 | }; | 846 | }; |
536 | 847 | ||
848 | static struct snd_kcontrol_new stac_dmux_mixer = { | ||
849 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
850 | .name = "Digital Input Source", | ||
851 | /* count set later */ | ||
852 | .info = stac92xx_dmux_enum_info, | ||
853 | .get = stac92xx_dmux_enum_get, | ||
854 | .put = stac92xx_dmux_enum_put, | ||
855 | }; | ||
856 | |||
857 | static const char *slave_vols[] = { | ||
858 | "Front Playback Volume", | ||
859 | "Surround Playback Volume", | ||
860 | "Center Playback Volume", | ||
861 | "LFE Playback Volume", | ||
862 | "Side Playback Volume", | ||
863 | "Headphone Playback Volume", | ||
864 | "Headphone Playback Volume", | ||
865 | "Speaker Playback Volume", | ||
866 | "External Speaker Playback Volume", | ||
867 | "Speaker2 Playback Volume", | ||
868 | NULL | ||
869 | }; | ||
870 | |||
871 | static const char *slave_sws[] = { | ||
872 | "Front Playback Switch", | ||
873 | "Surround Playback Switch", | ||
874 | "Center Playback Switch", | ||
875 | "LFE Playback Switch", | ||
876 | "Side Playback Switch", | ||
877 | "Headphone Playback Switch", | ||
878 | "Headphone Playback Switch", | ||
879 | "Speaker Playback Switch", | ||
880 | "External Speaker Playback Switch", | ||
881 | "Speaker2 Playback Switch", | ||
882 | "IEC958 Playback Switch", | ||
883 | NULL | ||
884 | }; | ||
885 | |||
537 | static int stac92xx_build_controls(struct hda_codec *codec) | 886 | static int stac92xx_build_controls(struct hda_codec *codec) |
538 | { | 887 | { |
539 | struct sigmatel_spec *spec = codec->spec; | 888 | struct sigmatel_spec *spec = codec->spec; |
@@ -549,6 +898,13 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
549 | if (err < 0) | 898 | if (err < 0) |
550 | return err; | 899 | return err; |
551 | } | 900 | } |
901 | if (spec->num_dmuxes > 0) { | ||
902 | stac_dmux_mixer.count = spec->num_dmuxes; | ||
903 | err = snd_ctl_add(codec->bus->card, | ||
904 | snd_ctl_new1(&stac_dmux_mixer, codec)); | ||
905 | if (err < 0) | ||
906 | return err; | ||
907 | } | ||
552 | 908 | ||
553 | if (spec->multiout.dig_out_nid) { | 909 | if (spec->multiout.dig_out_nid) { |
554 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | 910 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); |
@@ -560,6 +916,23 @@ static int stac92xx_build_controls(struct hda_codec *codec) | |||
560 | if (err < 0) | 916 | if (err < 0) |
561 | return err; | 917 | return err; |
562 | } | 918 | } |
919 | |||
920 | /* if we have no master control, let's create it */ | ||
921 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { | ||
922 | snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], | ||
923 | HDA_OUTPUT, spec->vmaster_tlv); | ||
924 | err = snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
925 | spec->vmaster_tlv, slave_vols); | ||
926 | if (err < 0) | ||
927 | return err; | ||
928 | } | ||
929 | if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { | ||
930 | err = snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
931 | NULL, slave_sws); | ||
932 | if (err < 0) | ||
933 | return err; | ||
934 | } | ||
935 | |||
563 | return 0; | 936 | return 0; |
564 | } | 937 | } |
565 | 938 | ||
@@ -785,7 +1158,7 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { | |||
785 | 1158 | ||
786 | static unsigned int ref925x_pin_configs[8] = { | 1159 | static unsigned int ref925x_pin_configs[8] = { |
787 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, | 1160 | 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, |
788 | 0x90a70320, 0x02214210, 0x400003f1, 0x9033032e, | 1161 | 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, |
789 | }; | 1162 | }; |
790 | 1163 | ||
791 | static unsigned int stac925x_MA6_pin_configs[8] = { | 1164 | static unsigned int stac925x_MA6_pin_configs[8] = { |
@@ -829,6 +1202,48 @@ static struct snd_pci_quirk stac925x_cfg_tbl[] = { | |||
829 | {} /* terminator */ | 1202 | {} /* terminator */ |
830 | }; | 1203 | }; |
831 | 1204 | ||
1205 | static unsigned int ref92hd73xx_pin_configs[12] = { | ||
1206 | 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, | ||
1207 | 0x0181302e, 0x01014010, 0x01014020, 0x01014030, | ||
1208 | 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, | ||
1209 | }; | ||
1210 | |||
1211 | static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { | ||
1212 | [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, | ||
1213 | }; | ||
1214 | |||
1215 | static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { | ||
1216 | [STAC_92HD73XX_REF] = "ref", | ||
1217 | }; | ||
1218 | |||
1219 | static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { | ||
1220 | /* SigmaTel reference board */ | ||
1221 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
1222 | "DFI LanParty", STAC_92HD73XX_REF), | ||
1223 | {} /* terminator */ | ||
1224 | }; | ||
1225 | |||
1226 | static unsigned int ref92hd71bxx_pin_configs[10] = { | ||
1227 | 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, | ||
1228 | 0x0181302e, 0x01114010, 0x01019020, 0x90a000f0, | ||
1229 | 0x90a000f0, 0x01452050, | ||
1230 | }; | ||
1231 | |||
1232 | static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { | ||
1233 | [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, | ||
1234 | }; | ||
1235 | |||
1236 | static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { | ||
1237 | [STAC_92HD71BXX_REF] = "ref", | ||
1238 | }; | ||
1239 | |||
1240 | static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { | ||
1241 | /* SigmaTel reference board */ | ||
1242 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | ||
1243 | "DFI LanParty", STAC_92HD71BXX_REF), | ||
1244 | {} /* terminator */ | ||
1245 | }; | ||
1246 | |||
832 | static unsigned int ref922x_pin_configs[10] = { | 1247 | static unsigned int ref922x_pin_configs[10] = { |
833 | 0x01014010, 0x01016011, 0x01012012, 0x0221401f, | 1248 | 0x01014010, 0x01016011, 0x01012012, 0x0221401f, |
834 | 0x01813122, 0x01011014, 0x01441030, 0x01c41030, | 1249 | 0x01813122, 0x01011014, 0x01441030, 0x01c41030, |
@@ -875,8 +1290,8 @@ static unsigned int dell_922x_m81_pin_configs[10] = { | |||
875 | 102801D7 (Dell XPS M1210) | 1290 | 102801D7 (Dell XPS M1210) |
876 | */ | 1291 | */ |
877 | static unsigned int dell_922x_m82_pin_configs[10] = { | 1292 | static unsigned int dell_922x_m82_pin_configs[10] = { |
878 | 0x0221121f, 0x408103ff, 0x02111212, 0x90100310, | 1293 | 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, |
879 | 0x408003f1, 0x02111211, 0x03451340, 0x40c003f2, | 1294 | 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, |
880 | 0x508003f3, 0x405003f4, | 1295 | 0x508003f3, 0x405003f4, |
881 | }; | 1296 | }; |
882 | 1297 | ||
@@ -1074,22 +1489,24 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
1074 | static unsigned int dell_3st_pin_configs[14] = { | 1489 | static unsigned int dell_3st_pin_configs[14] = { |
1075 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, | 1490 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, |
1076 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, | 1491 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, |
1077 | 0x403003fa, 0x40000100, 0x40000100, 0x404003fb, | 1492 | 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, |
1078 | 0x40c003fc, 0x40000100 | 1493 | 0x40c003fc, 0x40000100 |
1079 | }; | 1494 | }; |
1080 | 1495 | ||
1081 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | 1496 | static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { |
1082 | [STAC_D965_REF] = ref927x_pin_configs, | 1497 | [STAC_D965_REF] = ref927x_pin_configs, |
1083 | [STAC_D965_3ST] = d965_3st_pin_configs, | 1498 | [STAC_D965_3ST] = d965_3st_pin_configs, |
1084 | [STAC_D965_5ST] = d965_5st_pin_configs, | 1499 | [STAC_D965_5ST] = d965_5st_pin_configs, |
1085 | [STAC_DELL_3ST] = dell_3st_pin_configs, | 1500 | [STAC_DELL_3ST] = dell_3st_pin_configs, |
1501 | [STAC_DELL_BIOS] = NULL, | ||
1086 | }; | 1502 | }; |
1087 | 1503 | ||
1088 | static const char *stac927x_models[STAC_927X_MODELS] = { | 1504 | static const char *stac927x_models[STAC_927X_MODELS] = { |
1089 | [STAC_D965_REF] = "ref", | 1505 | [STAC_D965_REF] = "ref", |
1090 | [STAC_D965_3ST] = "3stack", | 1506 | [STAC_D965_3ST] = "3stack", |
1091 | [STAC_D965_5ST] = "5stack", | 1507 | [STAC_D965_5ST] = "5stack", |
1092 | [STAC_DELL_3ST] = "dell-3stack", | 1508 | [STAC_DELL_3ST] = "dell-3stack", |
1509 | [STAC_DELL_BIOS] = "dell-bios", | ||
1093 | }; | 1510 | }; |
1094 | 1511 | ||
1095 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { | 1512 | static struct snd_pci_quirk stac927x_cfg_tbl[] = { |
@@ -1116,13 +1533,21 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { | |||
1116 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), | 1533 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2003, "Intel D965", STAC_D965_3ST), |
1117 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), | 1534 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2002, "Intel D965", STAC_D965_3ST), |
1118 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), | 1535 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2001, "Intel D965", STAC_D965_3ST), |
1119 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_D965_3ST), | ||
1120 | /* Dell 3 stack systems */ | 1536 | /* Dell 3 stack systems */ |
1537 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_3ST), | ||
1121 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), | 1538 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01dd, "Dell Dimension E520", STAC_DELL_3ST), |
1122 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), | 1539 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ed, "Dell ", STAC_DELL_3ST), |
1123 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), | 1540 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f4, "Dell ", STAC_DELL_3ST), |
1541 | /* Dell 3 stack systems with verb table in BIOS */ | ||
1542 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), | ||
1543 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), | ||
1544 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell ", STAC_DELL_BIOS), | ||
1545 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), | ||
1546 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), | ||
1547 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), | ||
1548 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), | ||
1549 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS), | ||
1124 | /* 965 based 5 stack systems */ | 1550 | /* 965 based 5 stack systems */ |
1125 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_D965_5ST), | ||
1126 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), | 1551 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2301, "Intel D965", STAC_D965_5ST), |
1127 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), | 1552 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2302, "Intel D965", STAC_D965_5ST), |
1128 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), | 1553 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2303, "Intel D965", STAC_D965_5ST), |
@@ -1137,7 +1562,7 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = { | |||
1137 | 1562 | ||
1138 | static unsigned int ref9205_pin_configs[12] = { | 1563 | static unsigned int ref9205_pin_configs[12] = { |
1139 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, | 1564 | 0x40000100, 0x40000100, 0x01016011, 0x01014010, |
1140 | 0x01813122, 0x01a19021, 0x40000100, 0x40000100, | 1565 | 0x01813122, 0x01a19021, 0x01019020, 0x40000100, |
1141 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 | 1566 | 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 |
1142 | }; | 1567 | }; |
1143 | 1568 | ||
@@ -1149,6 +1574,7 @@ static unsigned int ref9205_pin_configs[12] = { | |||
1149 | 102801FD | 1574 | 102801FD |
1150 | 10280204 | 1575 | 10280204 |
1151 | 1028021F | 1576 | 1028021F |
1577 | 10280228 (Dell Vostro 1500) | ||
1152 | */ | 1578 | */ |
1153 | static unsigned int dell_9205_m42_pin_configs[12] = { | 1579 | static unsigned int dell_9205_m42_pin_configs[12] = { |
1154 | 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, | 1580 | 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, |
@@ -1232,6 +1658,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { | |||
1232 | "unknown Dell", STAC_9205_DELL_M42), | 1658 | "unknown Dell", STAC_9205_DELL_M42), |
1233 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, | 1659 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f, |
1234 | "Dell Inspiron", STAC_9205_DELL_M44), | 1660 | "Dell Inspiron", STAC_9205_DELL_M44), |
1661 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, | ||
1662 | "Dell Vostro 1500", STAC_9205_DELL_M42), | ||
1235 | {} /* terminator */ | 1663 | {} /* terminator */ |
1236 | }; | 1664 | }; |
1237 | 1665 | ||
@@ -1297,22 +1725,6 @@ static void stac92xx_set_config_regs(struct hda_codec *codec) | |||
1297 | spec->pin_configs[i]); | 1725 | spec->pin_configs[i]); |
1298 | } | 1726 | } |
1299 | 1727 | ||
1300 | static void stac92xx_enable_gpio_mask(struct hda_codec *codec) | ||
1301 | { | ||
1302 | struct sigmatel_spec *spec = codec->spec; | ||
1303 | /* Configure GPIOx as output */ | ||
1304 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1305 | AC_VERB_SET_GPIO_DIRECTION, spec->gpio_mask); | ||
1306 | /* Configure GPIOx as CMOS */ | ||
1307 | snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7e7, 0x00000000); | ||
1308 | /* Assert GPIOx */ | ||
1309 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1310 | AC_VERB_SET_GPIO_DATA, spec->gpio_data); | ||
1311 | /* Enable GPIOx */ | ||
1312 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
1313 | AC_VERB_SET_GPIO_MASK, spec->gpio_mask); | ||
1314 | } | ||
1315 | |||
1316 | /* | 1728 | /* |
1317 | * Analog playback callbacks | 1729 | * Analog playback callbacks |
1318 | */ | 1730 | */ |
@@ -1531,7 +1943,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1531 | struct sigmatel_spec *spec = codec->spec; | 1943 | struct sigmatel_spec *spec = codec->spec; |
1532 | hda_nid_t nid = kcontrol->private_value >> 8; | 1944 | hda_nid_t nid = kcontrol->private_value >> 8; |
1533 | int io_idx = kcontrol-> private_value & 0xff; | 1945 | int io_idx = kcontrol-> private_value & 0xff; |
1534 | unsigned short val = ucontrol->value.integer.value[0]; | 1946 | unsigned short val = !!ucontrol->value.integer.value[0]; |
1535 | 1947 | ||
1536 | spec->io_switch[io_idx] = val; | 1948 | spec->io_switch[io_idx] = val; |
1537 | 1949 | ||
@@ -1543,6 +1955,13 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1543 | pinctl |= stac92xx_get_vref(codec, nid); | 1955 | pinctl |= stac92xx_get_vref(codec, nid); |
1544 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 1956 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
1545 | } | 1957 | } |
1958 | |||
1959 | /* check the auto-mute again: we need to mute/unmute the speaker | ||
1960 | * appropriately according to the pin direction | ||
1961 | */ | ||
1962 | if (spec->hp_detect) | ||
1963 | codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); | ||
1964 | |||
1546 | return 1; | 1965 | return 1; |
1547 | } | 1966 | } |
1548 | 1967 | ||
@@ -1564,11 +1983,12 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
1564 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1983 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
1565 | struct sigmatel_spec *spec = codec->spec; | 1984 | struct sigmatel_spec *spec = codec->spec; |
1566 | hda_nid_t nid = kcontrol->private_value & 0xff; | 1985 | hda_nid_t nid = kcontrol->private_value & 0xff; |
1986 | unsigned int val = !!ucontrol->value.integer.value[0]; | ||
1567 | 1987 | ||
1568 | if (spec->clfe_swap == ucontrol->value.integer.value[0]) | 1988 | if (spec->clfe_swap == val) |
1569 | return 0; | 1989 | return 0; |
1570 | 1990 | ||
1571 | spec->clfe_swap = ucontrol->value.integer.value[0]; | 1991 | spec->clfe_swap = val; |
1572 | 1992 | ||
1573 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, | 1993 | snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, |
1574 | spec->clfe_swap ? 0x4 : 0x0); | 1994 | spec->clfe_swap ? 0x4 : 0x0); |
@@ -1599,6 +2019,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, | |||
1599 | enum { | 2019 | enum { |
1600 | STAC_CTL_WIDGET_VOL, | 2020 | STAC_CTL_WIDGET_VOL, |
1601 | STAC_CTL_WIDGET_MUTE, | 2021 | STAC_CTL_WIDGET_MUTE, |
2022 | STAC_CTL_WIDGET_MONO_MUX, | ||
1602 | STAC_CTL_WIDGET_IO_SWITCH, | 2023 | STAC_CTL_WIDGET_IO_SWITCH, |
1603 | STAC_CTL_WIDGET_CLFE_SWITCH | 2024 | STAC_CTL_WIDGET_CLFE_SWITCH |
1604 | }; | 2025 | }; |
@@ -1606,6 +2027,7 @@ enum { | |||
1606 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2027 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
1607 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), | 2028 | HDA_CODEC_VOLUME(NULL, 0, 0, 0), |
1608 | HDA_CODEC_MUTE(NULL, 0, 0, 0), | 2029 | HDA_CODEC_MUTE(NULL, 0, 0, 0), |
2030 | STAC_MONO_MUX, | ||
1609 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2031 | STAC_CODEC_IO_SWITCH(NULL, 0), |
1610 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | 2032 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
1611 | }; | 2033 | }; |
@@ -1650,6 +2072,7 @@ static int stac92xx_add_dyn_out_pins(struct hda_codec *codec, struct auto_pin_cf | |||
1650 | for (i = 0; i < codec->num_nodes; i++) { | 2072 | for (i = 0; i < codec->num_nodes; i++) { |
1651 | wcaps = codec->wcaps[i]; | 2073 | wcaps = codec->wcaps[i]; |
1652 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2074 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
2075 | |||
1653 | if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) | 2076 | if (wtype == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) |
1654 | num_dacs++; | 2077 | num_dacs++; |
1655 | } | 2078 | } |
@@ -1737,7 +2160,6 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, | |||
1737 | wcaps = snd_hda_param_read(codec, conn[j], | 2160 | wcaps = snd_hda_param_read(codec, conn[j], |
1738 | AC_PAR_AUDIO_WIDGET_CAP); | 2161 | AC_PAR_AUDIO_WIDGET_CAP); |
1739 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 2162 | wtype = (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
1740 | |||
1741 | if (wtype != AC_WID_AUD_OUT || | 2163 | if (wtype != AC_WID_AUD_OUT || |
1742 | (wcaps & AC_WCAP_DIGITAL)) | 2164 | (wcaps & AC_WCAP_DIGITAL)) |
1743 | continue; | 2165 | continue; |
@@ -1811,7 +2233,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
1811 | int i, err; | 2233 | int i, err; |
1812 | 2234 | ||
1813 | struct sigmatel_spec *spec = codec->spec; | 2235 | struct sigmatel_spec *spec = codec->spec; |
1814 | unsigned int wid_caps; | 2236 | unsigned int wid_caps, pincap; |
1815 | 2237 | ||
1816 | 2238 | ||
1817 | for (i = 0; i < cfg->line_outs; i++) { | 2239 | for (i = 0; i < cfg->line_outs; i++) { |
@@ -1847,13 +2269,39 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
1847 | } | 2269 | } |
1848 | } | 2270 | } |
1849 | 2271 | ||
1850 | if (spec->line_switch) | 2272 | if (spec->line_switch) { |
1851 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Line In as Output Switch", cfg->input_pins[AUTO_PIN_LINE] << 8)) < 0) | 2273 | nid = cfg->input_pins[AUTO_PIN_LINE]; |
1852 | return err; | 2274 | pincap = snd_hda_param_read(codec, nid, |
2275 | AC_PAR_PIN_CAP); | ||
2276 | if (pincap & AC_PINCAP_OUT) { | ||
2277 | err = stac92xx_add_control(spec, | ||
2278 | STAC_CTL_WIDGET_IO_SWITCH, | ||
2279 | "Line In as Output Switch", nid << 8); | ||
2280 | if (err < 0) | ||
2281 | return err; | ||
2282 | } | ||
2283 | } | ||
1853 | 2284 | ||
1854 | if (spec->mic_switch) | 2285 | if (spec->mic_switch) { |
1855 | if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, "Mic as Output Switch", (cfg->input_pins[AUTO_PIN_MIC] << 8) | 1)) < 0) | 2286 | unsigned int def_conf; |
1856 | return err; | 2287 | nid = cfg->input_pins[AUTO_PIN_MIC]; |
2288 | def_conf = snd_hda_codec_read(codec, nid, 0, | ||
2289 | AC_VERB_GET_CONFIG_DEFAULT, 0); | ||
2290 | |||
2291 | /* some laptops have an internal analog microphone | ||
2292 | * which can't be used as a output */ | ||
2293 | if (get_defcfg_connect(def_conf) != AC_JACK_PORT_FIXED) { | ||
2294 | pincap = snd_hda_param_read(codec, nid, | ||
2295 | AC_PAR_PIN_CAP); | ||
2296 | if (pincap & AC_PINCAP_OUT) { | ||
2297 | err = stac92xx_add_control(spec, | ||
2298 | STAC_CTL_WIDGET_IO_SWITCH, | ||
2299 | "Mic as Output Switch", (nid << 8) | 1); | ||
2300 | if (err < 0) | ||
2301 | return err; | ||
2302 | } | ||
2303 | } | ||
2304 | } | ||
1857 | 2305 | ||
1858 | return 0; | 2306 | return 0; |
1859 | } | 2307 | } |
@@ -1931,8 +2379,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, | |||
1931 | } | 2379 | } |
1932 | if (spec->multiout.hp_nid) { | 2380 | if (spec->multiout.hp_nid) { |
1933 | const char *pfx; | 2381 | const char *pfx; |
1934 | if (old_num_dacs == spec->multiout.num_dacs && | 2382 | if (old_num_dacs == spec->multiout.num_dacs) |
1935 | spec->no_vol_knob) | ||
1936 | pfx = "Master"; | 2383 | pfx = "Master"; |
1937 | else | 2384 | else |
1938 | pfx = "Headphone"; | 2385 | pfx = "Headphone"; |
@@ -1944,6 +2391,37 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, | |||
1944 | return 0; | 2391 | return 0; |
1945 | } | 2392 | } |
1946 | 2393 | ||
2394 | /* labels for mono mux outputs */ | ||
2395 | static const char *stac92xx_mono_labels[3] = { | ||
2396 | "DAC0", "DAC1", "Mixer" | ||
2397 | }; | ||
2398 | |||
2399 | /* create mono mux for mono out on capable codecs */ | ||
2400 | static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) | ||
2401 | { | ||
2402 | struct sigmatel_spec *spec = codec->spec; | ||
2403 | struct hda_input_mux *mono_mux = &spec->private_mono_mux; | ||
2404 | int i, num_cons; | ||
2405 | hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)]; | ||
2406 | |||
2407 | num_cons = snd_hda_get_connections(codec, | ||
2408 | spec->mono_nid, | ||
2409 | con_lst, | ||
2410 | HDA_MAX_NUM_INPUTS); | ||
2411 | if (!num_cons || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) | ||
2412 | return -EINVAL; | ||
2413 | |||
2414 | for (i = 0; i < num_cons; i++) { | ||
2415 | mono_mux->items[mono_mux->num_items].label = | ||
2416 | stac92xx_mono_labels[i]; | ||
2417 | mono_mux->items[mono_mux->num_items].index = i; | ||
2418 | mono_mux->num_items++; | ||
2419 | } | ||
2420 | |||
2421 | return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX, | ||
2422 | "Mono Mux", spec->mono_nid); | ||
2423 | } | ||
2424 | |||
1947 | /* labels for dmic mux inputs */ | 2425 | /* labels for dmic mux inputs */ |
1948 | static const char *stac92xx_dmic_labels[5] = { | 2426 | static const char *stac92xx_dmic_labels[5] = { |
1949 | "Analog Inputs", "Digital Mic 1", "Digital Mic 2", | 2427 | "Analog Inputs", "Digital Mic 1", "Digital Mic 2", |
@@ -1957,15 +2435,18 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, | |||
1957 | struct sigmatel_spec *spec = codec->spec; | 2435 | struct sigmatel_spec *spec = codec->spec; |
1958 | struct hda_input_mux *dimux = &spec->private_dimux; | 2436 | struct hda_input_mux *dimux = &spec->private_dimux; |
1959 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; | 2437 | hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; |
1960 | int i, j; | 2438 | int err, i, j; |
2439 | char name[32]; | ||
1961 | 2440 | ||
1962 | dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; | 2441 | dimux->items[dimux->num_items].label = stac92xx_dmic_labels[0]; |
1963 | dimux->items[dimux->num_items].index = 0; | 2442 | dimux->items[dimux->num_items].index = 0; |
1964 | dimux->num_items++; | 2443 | dimux->num_items++; |
1965 | 2444 | ||
1966 | for (i = 0; i < spec->num_dmics; i++) { | 2445 | for (i = 0; i < spec->num_dmics; i++) { |
2446 | hda_nid_t nid; | ||
1967 | int index; | 2447 | int index; |
1968 | int num_cons; | 2448 | int num_cons; |
2449 | unsigned int wcaps; | ||
1969 | unsigned int def_conf; | 2450 | unsigned int def_conf; |
1970 | 2451 | ||
1971 | def_conf = snd_hda_codec_read(codec, | 2452 | def_conf = snd_hda_codec_read(codec, |
@@ -1976,17 +2457,32 @@ static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, | |||
1976 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) | 2457 | if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) |
1977 | continue; | 2458 | continue; |
1978 | 2459 | ||
2460 | nid = spec->dmic_nids[i]; | ||
1979 | num_cons = snd_hda_get_connections(codec, | 2461 | num_cons = snd_hda_get_connections(codec, |
1980 | spec->dmux_nid, | 2462 | spec->dmux_nids[0], |
1981 | con_lst, | 2463 | con_lst, |
1982 | HDA_MAX_NUM_INPUTS); | 2464 | HDA_MAX_NUM_INPUTS); |
1983 | for (j = 0; j < num_cons; j++) | 2465 | for (j = 0; j < num_cons; j++) |
1984 | if (con_lst[j] == spec->dmic_nids[i]) { | 2466 | if (con_lst[j] == nid) { |
1985 | index = j; | 2467 | index = j; |
1986 | goto found; | 2468 | goto found; |
1987 | } | 2469 | } |
1988 | continue; | 2470 | continue; |
1989 | found: | 2471 | found: |
2472 | wcaps = get_wcaps(codec, nid); | ||
2473 | |||
2474 | if (wcaps & AC_WCAP_OUT_AMP) { | ||
2475 | sprintf(name, "%s Capture Volume", | ||
2476 | stac92xx_dmic_labels[dimux->num_items]); | ||
2477 | |||
2478 | err = stac92xx_add_control(spec, | ||
2479 | STAC_CTL_WIDGET_VOL, | ||
2480 | name, | ||
2481 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | ||
2482 | if (err < 0) | ||
2483 | return err; | ||
2484 | } | ||
2485 | |||
1990 | dimux->items[dimux->num_items].label = | 2486 | dimux->items[dimux->num_items].label = |
1991 | stac92xx_dmic_labels[dimux->num_items]; | 2487 | stac92xx_dmic_labels[dimux->num_items]; |
1992 | dimux->items[dimux->num_items].index = index; | 2488 | dimux->items[dimux->num_items].index = index; |
@@ -2079,6 +2575,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2079 | { | 2575 | { |
2080 | struct sigmatel_spec *spec = codec->spec; | 2576 | struct sigmatel_spec *spec = codec->spec; |
2081 | int err; | 2577 | int err; |
2578 | int hp_speaker_swap = 0; | ||
2082 | 2579 | ||
2083 | if ((err = snd_hda_parse_pin_def_config(codec, | 2580 | if ((err = snd_hda_parse_pin_def_config(codec, |
2084 | &spec->autocfg, | 2581 | &spec->autocfg, |
@@ -2087,6 +2584,68 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2087 | if (! spec->autocfg.line_outs) | 2584 | if (! spec->autocfg.line_outs) |
2088 | return 0; /* can't find valid pin config */ | 2585 | return 0; /* can't find valid pin config */ |
2089 | 2586 | ||
2587 | /* If we have no real line-out pin and multiple hp-outs, HPs should | ||
2588 | * be set up as multi-channel outputs. | ||
2589 | */ | ||
2590 | if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && | ||
2591 | spec->autocfg.hp_outs > 1) { | ||
2592 | /* Copy hp_outs to line_outs, backup line_outs in | ||
2593 | * speaker_outs so that the following routines can handle | ||
2594 | * HP pins as primary outputs. | ||
2595 | */ | ||
2596 | memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, | ||
2597 | sizeof(spec->autocfg.line_out_pins)); | ||
2598 | spec->autocfg.speaker_outs = spec->autocfg.line_outs; | ||
2599 | memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, | ||
2600 | sizeof(spec->autocfg.hp_pins)); | ||
2601 | spec->autocfg.line_outs = spec->autocfg.hp_outs; | ||
2602 | hp_speaker_swap = 1; | ||
2603 | } | ||
2604 | if (spec->autocfg.mono_out_pin) { | ||
2605 | int dir = (get_wcaps(codec, spec->autocfg.mono_out_pin) | ||
2606 | & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; | ||
2607 | u32 caps = query_amp_caps(codec, | ||
2608 | spec->autocfg.mono_out_pin, dir); | ||
2609 | hda_nid_t conn_list[1]; | ||
2610 | |||
2611 | /* get the mixer node and then the mono mux if it exists */ | ||
2612 | if (snd_hda_get_connections(codec, | ||
2613 | spec->autocfg.mono_out_pin, conn_list, 1) && | ||
2614 | snd_hda_get_connections(codec, conn_list[0], | ||
2615 | conn_list, 1)) { | ||
2616 | |||
2617 | int wcaps = get_wcaps(codec, conn_list[0]); | ||
2618 | int wid_type = (wcaps & AC_WCAP_TYPE) | ||
2619 | >> AC_WCAP_TYPE_SHIFT; | ||
2620 | /* LR swap check, some stac925x have a mux that | ||
2621 | * changes the DACs output path instead of the | ||
2622 | * mono-mux path. | ||
2623 | */ | ||
2624 | if (wid_type == AC_WID_AUD_SEL && | ||
2625 | !(wcaps & AC_WCAP_LR_SWAP)) | ||
2626 | spec->mono_nid = conn_list[0]; | ||
2627 | } | ||
2628 | /* all mono outs have a least a mute/unmute switch */ | ||
2629 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, | ||
2630 | "Mono Playback Switch", | ||
2631 | HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, | ||
2632 | 1, 0, dir)); | ||
2633 | if (err < 0) | ||
2634 | return err; | ||
2635 | /* check to see if there is volume support for the amp */ | ||
2636 | if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { | ||
2637 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, | ||
2638 | "Mono Playback Volume", | ||
2639 | HDA_COMPOSE_AMP_VAL(spec->autocfg.mono_out_pin, | ||
2640 | 1, 0, dir)); | ||
2641 | if (err < 0) | ||
2642 | return err; | ||
2643 | } | ||
2644 | |||
2645 | stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin, | ||
2646 | AC_PINCTL_OUT_EN); | ||
2647 | } | ||
2648 | |||
2090 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) | 2649 | if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0) |
2091 | return err; | 2650 | return err; |
2092 | if (spec->multiout.num_dacs == 0) | 2651 | if (spec->multiout.num_dacs == 0) |
@@ -2098,6 +2657,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2098 | if (err < 0) | 2657 | if (err < 0) |
2099 | return err; | 2658 | return err; |
2100 | 2659 | ||
2660 | if (hp_speaker_swap == 1) { | ||
2661 | /* Restore the hp_outs and line_outs */ | ||
2662 | memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, | ||
2663 | sizeof(spec->autocfg.line_out_pins)); | ||
2664 | spec->autocfg.hp_outs = spec->autocfg.line_outs; | ||
2665 | memcpy(spec->autocfg.line_out_pins, spec->autocfg.speaker_pins, | ||
2666 | sizeof(spec->autocfg.speaker_pins)); | ||
2667 | spec->autocfg.line_outs = spec->autocfg.speaker_outs; | ||
2668 | memset(spec->autocfg.speaker_pins, 0, | ||
2669 | sizeof(spec->autocfg.speaker_pins)); | ||
2670 | spec->autocfg.speaker_outs = 0; | ||
2671 | } | ||
2672 | |||
2101 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); | 2673 | err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); |
2102 | 2674 | ||
2103 | if (err < 0) | 2675 | if (err < 0) |
@@ -2108,6 +2680,12 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2108 | if (err < 0) | 2680 | if (err < 0) |
2109 | return err; | 2681 | return err; |
2110 | 2682 | ||
2683 | if (spec->mono_nid > 0) { | ||
2684 | err = stac92xx_auto_create_mono_output_ctls(codec); | ||
2685 | if (err < 0) | ||
2686 | return err; | ||
2687 | } | ||
2688 | |||
2111 | if (spec->num_dmics > 0) | 2689 | if (spec->num_dmics > 0) |
2112 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, | 2690 | if ((err = stac92xx_auto_create_dmic_input_ctls(codec, |
2113 | &spec->autocfg)) < 0) | 2691 | &spec->autocfg)) < 0) |
@@ -2126,7 +2704,9 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
2126 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | 2704 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; |
2127 | 2705 | ||
2128 | spec->input_mux = &spec->private_imux; | 2706 | spec->input_mux = &spec->private_imux; |
2129 | spec->dinput_mux = &spec->private_dimux; | 2707 | if (!spec->dinput_mux) |
2708 | spec->dinput_mux = &spec->private_dimux; | ||
2709 | spec->mono_mux = &spec->private_mono_mux; | ||
2130 | 2710 | ||
2131 | return 1; | 2711 | return 1; |
2132 | } | 2712 | } |
@@ -2236,38 +2816,35 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
2236 | * funky external mute control using GPIO pins. | 2816 | * funky external mute control using GPIO pins. |
2237 | */ | 2817 | */ |
2238 | 2818 | ||
2239 | static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) | 2819 | static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, |
2820 | unsigned int dir_mask, unsigned int data) | ||
2240 | { | 2821 | { |
2241 | unsigned int gpiostate, gpiomask, gpiodir; | 2822 | unsigned int gpiostate, gpiomask, gpiodir; |
2242 | 2823 | ||
2243 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, | 2824 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, |
2244 | AC_VERB_GET_GPIO_DATA, 0); | 2825 | AC_VERB_GET_GPIO_DATA, 0); |
2245 | 2826 | gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); | |
2246 | if (!muted) | ||
2247 | gpiostate |= (1 << pin); | ||
2248 | else | ||
2249 | gpiostate &= ~(1 << pin); | ||
2250 | 2827 | ||
2251 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, | 2828 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, |
2252 | AC_VERB_GET_GPIO_MASK, 0); | 2829 | AC_VERB_GET_GPIO_MASK, 0); |
2253 | gpiomask |= (1 << pin); | 2830 | gpiomask |= mask; |
2254 | 2831 | ||
2255 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, | 2832 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, |
2256 | AC_VERB_GET_GPIO_DIRECTION, 0); | 2833 | AC_VERB_GET_GPIO_DIRECTION, 0); |
2257 | gpiodir |= (1 << pin); | 2834 | gpiodir |= dir_mask; |
2258 | 2835 | ||
2259 | /* AppleHDA seems to do this -- WTF is this verb?? */ | 2836 | /* Configure GPIOx as CMOS */ |
2260 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); | 2837 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); |
2261 | 2838 | ||
2262 | snd_hda_codec_write(codec, codec->afg, 0, | 2839 | snd_hda_codec_write(codec, codec->afg, 0, |
2263 | AC_VERB_SET_GPIO_MASK, gpiomask); | 2840 | AC_VERB_SET_GPIO_MASK, gpiomask); |
2264 | snd_hda_codec_write(codec, codec->afg, 0, | 2841 | snd_hda_codec_read(codec, codec->afg, 0, |
2265 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); | 2842 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ |
2266 | 2843 | ||
2267 | msleep(1); | 2844 | msleep(1); |
2268 | 2845 | ||
2269 | snd_hda_codec_write(codec, codec->afg, 0, | 2846 | snd_hda_codec_read(codec, codec->afg, 0, |
2270 | AC_VERB_SET_GPIO_DATA, gpiostate); | 2847 | AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ |
2271 | } | 2848 | } |
2272 | 2849 | ||
2273 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | 2850 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, |
@@ -2279,6 +2856,16 @@ static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | |||
2279 | (AC_USRSP_EN | event)); | 2856 | (AC_USRSP_EN | event)); |
2280 | } | 2857 | } |
2281 | 2858 | ||
2859 | static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) | ||
2860 | { | ||
2861 | int i; | ||
2862 | for (i = 0; i < cfg->hp_outs; i++) | ||
2863 | if (cfg->hp_pins[i] == nid) | ||
2864 | return 1; /* nid is a HP-Out */ | ||
2865 | |||
2866 | return 0; /* nid is not a HP-Out */ | ||
2867 | }; | ||
2868 | |||
2282 | static int stac92xx_init(struct hda_codec *codec) | 2869 | static int stac92xx_init(struct hda_codec *codec) |
2283 | { | 2870 | { |
2284 | struct sigmatel_spec *spec = codec->spec; | 2871 | struct sigmatel_spec *spec = codec->spec; |
@@ -2314,10 +2901,23 @@ static int stac92xx_init(struct hda_codec *codec) | |||
2314 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 2901 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
2315 | } | 2902 | } |
2316 | } | 2903 | } |
2317 | if (spec->num_dmics > 0) | 2904 | for (i = 0; i < spec->num_dmics; i++) |
2318 | for (i = 0; i < spec->num_dmics; i++) | 2905 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], |
2319 | stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], | 2906 | AC_PINCTL_IN_EN); |
2320 | AC_PINCTL_IN_EN); | 2907 | for (i = 0; i < spec->num_pwrs; i++) { |
2908 | int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) | ||
2909 | ? STAC_HP_EVENT : STAC_PWR_EVENT; | ||
2910 | int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i], | ||
2911 | 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
2912 | /* outputs are only ports capable of power management | ||
2913 | * any attempts on powering down a input port cause the | ||
2914 | * referenced VREF to act quirky. | ||
2915 | */ | ||
2916 | if (pinctl & AC_PINCTL_IN_EN) | ||
2917 | continue; | ||
2918 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | ||
2919 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | ||
2920 | } | ||
2321 | 2921 | ||
2322 | if (cfg->dig_out_pin) | 2922 | if (cfg->dig_out_pin) |
2323 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, | 2923 | stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, |
@@ -2326,10 +2926,8 @@ static int stac92xx_init(struct hda_codec *codec) | |||
2326 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, | 2926 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, |
2327 | AC_PINCTL_IN_EN); | 2927 | AC_PINCTL_IN_EN); |
2328 | 2928 | ||
2329 | if (spec->gpio_mute) { | 2929 | stac_gpio_set(codec, spec->gpio_mask, |
2330 | stac922x_gpio_mute(codec, 0, 0); | 2930 | spec->gpio_dir, spec->gpio_data); |
2331 | stac922x_gpio_mute(codec, 1, 0); | ||
2332 | } | ||
2333 | 2931 | ||
2334 | return 0; | 2932 | return 0; |
2335 | } | 2933 | } |
@@ -2395,13 +2993,20 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, | |||
2395 | pin_ctl & ~flag); | 2993 | pin_ctl & ~flag); |
2396 | } | 2994 | } |
2397 | 2995 | ||
2398 | static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) | 2996 | static int get_hp_pin_presence(struct hda_codec *codec, hda_nid_t nid) |
2399 | { | 2997 | { |
2400 | if (!nid) | 2998 | if (!nid) |
2401 | return 0; | 2999 | return 0; |
2402 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) | 3000 | if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) |
2403 | & (1 << 31)) | 3001 | & (1 << 31)) { |
2404 | return 1; | 3002 | unsigned int pinctl; |
3003 | pinctl = snd_hda_codec_read(codec, nid, 0, | ||
3004 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
3005 | if (pinctl & AC_PINCTL_IN_EN) | ||
3006 | return 0; /* mic- or line-input */ | ||
3007 | else | ||
3008 | return 1; /* HP-output */ | ||
3009 | } | ||
2405 | return 0; | 3010 | return 0; |
2406 | } | 3011 | } |
2407 | 3012 | ||
@@ -2412,10 +3017,14 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
2412 | int i, presence; | 3017 | int i, presence; |
2413 | 3018 | ||
2414 | presence = 0; | 3019 | presence = 0; |
3020 | if (spec->gpio_mute) | ||
3021 | presence = !(snd_hda_codec_read(codec, codec->afg, 0, | ||
3022 | AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); | ||
3023 | |||
2415 | for (i = 0; i < cfg->hp_outs; i++) { | 3024 | for (i = 0; i < cfg->hp_outs; i++) { |
2416 | presence = get_pin_presence(codec, cfg->hp_pins[i]); | ||
2417 | if (presence) | 3025 | if (presence) |
2418 | break; | 3026 | break; |
3027 | presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); | ||
2419 | } | 3028 | } |
2420 | 3029 | ||
2421 | if (presence) { | 3030 | if (presence) { |
@@ -2437,12 +3046,37 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | |||
2437 | } | 3046 | } |
2438 | } | 3047 | } |
2439 | 3048 | ||
3049 | static void stac92xx_pin_sense(struct hda_codec *codec, int idx) | ||
3050 | { | ||
3051 | struct sigmatel_spec *spec = codec->spec; | ||
3052 | hda_nid_t nid = spec->pwr_nids[idx]; | ||
3053 | int presence, val; | ||
3054 | val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) | ||
3055 | & 0x000000ff; | ||
3056 | presence = get_hp_pin_presence(codec, nid); | ||
3057 | idx = 1 << idx; | ||
3058 | |||
3059 | if (presence) | ||
3060 | val &= ~idx; | ||
3061 | else | ||
3062 | val |= idx; | ||
3063 | |||
3064 | /* power down unused output ports */ | ||
3065 | snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); | ||
3066 | }; | ||
3067 | |||
2440 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 3068 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) |
2441 | { | 3069 | { |
2442 | switch (res >> 26) { | 3070 | struct sigmatel_spec *spec = codec->spec; |
3071 | int idx = res >> 26 & 0x0f; | ||
3072 | |||
3073 | switch ((res >> 26) & 0x30) { | ||
2443 | case STAC_HP_EVENT: | 3074 | case STAC_HP_EVENT: |
2444 | stac92xx_hp_detect(codec, res); | 3075 | stac92xx_hp_detect(codec, res); |
2445 | break; | 3076 | /* fallthru */ |
3077 | case STAC_PWR_EVENT: | ||
3078 | if (spec->num_pwrs > 0) | ||
3079 | stac92xx_pin_sense(codec, idx); | ||
2446 | } | 3080 | } |
2447 | } | 3081 | } |
2448 | 3082 | ||
@@ -2453,10 +3087,8 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
2453 | 3087 | ||
2454 | stac92xx_set_config_regs(codec); | 3088 | stac92xx_set_config_regs(codec); |
2455 | snd_hda_sequence_write(codec, spec->init); | 3089 | snd_hda_sequence_write(codec, spec->init); |
2456 | if (spec->gpio_mute) { | 3090 | stac_gpio_set(codec, spec->gpio_mask, |
2457 | stac922x_gpio_mute(codec, 0, 0); | 3091 | spec->gpio_dir, spec->gpio_data); |
2458 | stac922x_gpio_mute(codec, 1, 0); | ||
2459 | } | ||
2460 | snd_hda_codec_resume_amp(codec); | 3092 | snd_hda_codec_resume_amp(codec); |
2461 | snd_hda_codec_resume_cache(codec); | 3093 | snd_hda_codec_resume_cache(codec); |
2462 | /* invoke unsolicited event to reset the HP state */ | 3094 | /* invoke unsolicited event to reset the HP state */ |
@@ -2489,7 +3121,6 @@ static int patch_stac9200(struct hda_codec *codec) | |||
2489 | codec->spec = spec; | 3121 | codec->spec = spec; |
2490 | spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); | 3122 | spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); |
2491 | spec->pin_nids = stac9200_pin_nids; | 3123 | spec->pin_nids = stac9200_pin_nids; |
2492 | spec->no_vol_knob = 1; | ||
2493 | spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, | 3124 | spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, |
2494 | stac9200_models, | 3125 | stac9200_models, |
2495 | stac9200_cfg_tbl); | 3126 | stac9200_cfg_tbl); |
@@ -2514,6 +3145,7 @@ static int patch_stac9200(struct hda_codec *codec) | |||
2514 | spec->num_muxes = 1; | 3145 | spec->num_muxes = 1; |
2515 | spec->num_dmics = 0; | 3146 | spec->num_dmics = 0; |
2516 | spec->num_adcs = 1; | 3147 | spec->num_adcs = 1; |
3148 | spec->num_pwrs = 0; | ||
2517 | 3149 | ||
2518 | if (spec->board_config == STAC_9200_GATEWAY) | 3150 | if (spec->board_config == STAC_9200_GATEWAY) |
2519 | spec->init = stac9200_eapd_init; | 3151 | spec->init = stac9200_eapd_init; |
@@ -2544,7 +3176,6 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2544 | codec->spec = spec; | 3176 | codec->spec = spec; |
2545 | spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); | 3177 | spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); |
2546 | spec->pin_nids = stac925x_pin_nids; | 3178 | spec->pin_nids = stac925x_pin_nids; |
2547 | spec->no_vol_knob = 1; | ||
2548 | spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, | 3179 | spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS, |
2549 | stac925x_models, | 3180 | stac925x_models, |
2550 | stac925x_cfg_tbl); | 3181 | stac925x_cfg_tbl); |
@@ -2570,6 +3201,7 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2570 | spec->mux_nids = stac925x_mux_nids; | 3201 | spec->mux_nids = stac925x_mux_nids; |
2571 | spec->num_muxes = 1; | 3202 | spec->num_muxes = 1; |
2572 | spec->num_adcs = 1; | 3203 | spec->num_adcs = 1; |
3204 | spec->num_pwrs = 0; | ||
2573 | switch (codec->vendor_id) { | 3205 | switch (codec->vendor_id) { |
2574 | case 0x83847632: /* STAC9202 */ | 3206 | case 0x83847632: /* STAC9202 */ |
2575 | case 0x83847633: /* STAC9202D */ | 3207 | case 0x83847633: /* STAC9202D */ |
@@ -2577,6 +3209,8 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2577 | case 0x83847637: /* STAC9251D */ | 3209 | case 0x83847637: /* STAC9251D */ |
2578 | spec->num_dmics = STAC925X_NUM_DMICS; | 3210 | spec->num_dmics = STAC925X_NUM_DMICS; |
2579 | spec->dmic_nids = stac925x_dmic_nids; | 3211 | spec->dmic_nids = stac925x_dmic_nids; |
3212 | spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids); | ||
3213 | spec->dmux_nids = stac925x_dmux_nids; | ||
2580 | break; | 3214 | break; |
2581 | default: | 3215 | default: |
2582 | spec->num_dmics = 0; | 3216 | spec->num_dmics = 0; |
@@ -2606,6 +3240,204 @@ static int patch_stac925x(struct hda_codec *codec) | |||
2606 | return 0; | 3240 | return 0; |
2607 | } | 3241 | } |
2608 | 3242 | ||
3243 | static struct hda_input_mux stac92hd73xx_dmux = { | ||
3244 | .num_items = 4, | ||
3245 | .items = { | ||
3246 | { "Analog Inputs", 0x0b }, | ||
3247 | { "CD", 0x08 }, | ||
3248 | { "Digital Mic 1", 0x09 }, | ||
3249 | { "Digital Mic 2", 0x0a }, | ||
3250 | } | ||
3251 | }; | ||
3252 | |||
3253 | static int patch_stac92hd73xx(struct hda_codec *codec) | ||
3254 | { | ||
3255 | struct sigmatel_spec *spec; | ||
3256 | hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; | ||
3257 | int err = 0; | ||
3258 | |||
3259 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3260 | if (spec == NULL) | ||
3261 | return -ENOMEM; | ||
3262 | |||
3263 | codec->spec = spec; | ||
3264 | spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); | ||
3265 | spec->pin_nids = stac92hd73xx_pin_nids; | ||
3266 | spec->board_config = snd_hda_check_board_config(codec, | ||
3267 | STAC_92HD73XX_MODELS, | ||
3268 | stac92hd73xx_models, | ||
3269 | stac92hd73xx_cfg_tbl); | ||
3270 | again: | ||
3271 | if (spec->board_config < 0) { | ||
3272 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3273 | " STAC92HD73XX, using BIOS defaults\n"); | ||
3274 | err = stac92xx_save_bios_config_regs(codec); | ||
3275 | if (err < 0) { | ||
3276 | stac92xx_free(codec); | ||
3277 | return err; | ||
3278 | } | ||
3279 | spec->pin_configs = spec->bios_pin_configs; | ||
3280 | } else { | ||
3281 | spec->pin_configs = stac92hd73xx_brd_tbl[spec->board_config]; | ||
3282 | stac92xx_set_config_regs(codec); | ||
3283 | } | ||
3284 | |||
3285 | spec->multiout.num_dacs = snd_hda_get_connections(codec, 0x0a, | ||
3286 | conn, STAC92HD73_DAC_COUNT + 2) - 1; | ||
3287 | |||
3288 | if (spec->multiout.num_dacs < 0) { | ||
3289 | printk(KERN_WARNING "hda_codec: Could not determine " | ||
3290 | "number of channels defaulting to DAC count\n"); | ||
3291 | spec->multiout.num_dacs = STAC92HD73_DAC_COUNT; | ||
3292 | } | ||
3293 | |||
3294 | switch (spec->multiout.num_dacs) { | ||
3295 | case 0x3: /* 6 Channel */ | ||
3296 | spec->mixer = stac92hd73xx_6ch_mixer; | ||
3297 | spec->init = stac92hd73xx_6ch_core_init; | ||
3298 | break; | ||
3299 | case 0x4: /* 8 Channel */ | ||
3300 | spec->multiout.hp_nid = 0x18; | ||
3301 | spec->mixer = stac92hd73xx_8ch_mixer; | ||
3302 | spec->init = stac92hd73xx_8ch_core_init; | ||
3303 | break; | ||
3304 | case 0x5: /* 10 Channel */ | ||
3305 | spec->multiout.hp_nid = 0x19; | ||
3306 | spec->mixer = stac92hd73xx_10ch_mixer; | ||
3307 | spec->init = stac92hd73xx_10ch_core_init; | ||
3308 | }; | ||
3309 | |||
3310 | spec->multiout.dac_nids = stac92hd73xx_dac_nids; | ||
3311 | spec->aloopback_mask = 0x01; | ||
3312 | spec->aloopback_shift = 8; | ||
3313 | |||
3314 | spec->mux_nids = stac92hd73xx_mux_nids; | ||
3315 | spec->adc_nids = stac92hd73xx_adc_nids; | ||
3316 | spec->dmic_nids = stac92hd73xx_dmic_nids; | ||
3317 | spec->dmux_nids = stac92hd73xx_dmux_nids; | ||
3318 | |||
3319 | spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); | ||
3320 | spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); | ||
3321 | spec->num_dmics = STAC92HD73XX_NUM_DMICS; | ||
3322 | spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); | ||
3323 | spec->dinput_mux = &stac92hd73xx_dmux; | ||
3324 | /* GPIO0 High = Enable EAPD */ | ||
3325 | spec->gpio_mask = spec->gpio_dir = 0x1; | ||
3326 | spec->gpio_data = 0x01; | ||
3327 | |||
3328 | spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); | ||
3329 | spec->pwr_nids = stac92hd73xx_pwr_nids; | ||
3330 | |||
3331 | err = stac92xx_parse_auto_config(codec, 0x22, 0x24); | ||
3332 | |||
3333 | if (!err) { | ||
3334 | if (spec->board_config < 0) { | ||
3335 | printk(KERN_WARNING "hda_codec: No auto-config is " | ||
3336 | "available, default to model=ref\n"); | ||
3337 | spec->board_config = STAC_92HD73XX_REF; | ||
3338 | goto again; | ||
3339 | } | ||
3340 | err = -EINVAL; | ||
3341 | } | ||
3342 | |||
3343 | if (err < 0) { | ||
3344 | stac92xx_free(codec); | ||
3345 | return err; | ||
3346 | } | ||
3347 | |||
3348 | codec->patch_ops = stac92xx_patch_ops; | ||
3349 | |||
3350 | return 0; | ||
3351 | } | ||
3352 | |||
3353 | static int patch_stac92hd71bxx(struct hda_codec *codec) | ||
3354 | { | ||
3355 | struct sigmatel_spec *spec; | ||
3356 | int err = 0; | ||
3357 | |||
3358 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
3359 | if (spec == NULL) | ||
3360 | return -ENOMEM; | ||
3361 | |||
3362 | codec->spec = spec; | ||
3363 | spec->num_pins = ARRAY_SIZE(stac92hd71bxx_pin_nids); | ||
3364 | spec->pin_nids = stac92hd71bxx_pin_nids; | ||
3365 | spec->board_config = snd_hda_check_board_config(codec, | ||
3366 | STAC_92HD71BXX_MODELS, | ||
3367 | stac92hd71bxx_models, | ||
3368 | stac92hd71bxx_cfg_tbl); | ||
3369 | again: | ||
3370 | if (spec->board_config < 0) { | ||
3371 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3372 | " STAC92HD71BXX, using BIOS defaults\n"); | ||
3373 | err = stac92xx_save_bios_config_regs(codec); | ||
3374 | if (err < 0) { | ||
3375 | stac92xx_free(codec); | ||
3376 | return err; | ||
3377 | } | ||
3378 | spec->pin_configs = spec->bios_pin_configs; | ||
3379 | } else { | ||
3380 | spec->pin_configs = stac92hd71bxx_brd_tbl[spec->board_config]; | ||
3381 | stac92xx_set_config_regs(codec); | ||
3382 | } | ||
3383 | |||
3384 | switch (codec->vendor_id) { | ||
3385 | case 0x111d76b6: /* 4 Port without Analog Mixer */ | ||
3386 | case 0x111d76b7: | ||
3387 | case 0x111d76b4: /* 6 Port without Analog Mixer */ | ||
3388 | case 0x111d76b5: | ||
3389 | spec->mixer = stac92hd71bxx_mixer; | ||
3390 | spec->init = stac92hd71bxx_core_init; | ||
3391 | break; | ||
3392 | default: | ||
3393 | spec->mixer = stac92hd71bxx_analog_mixer; | ||
3394 | spec->init = stac92hd71bxx_analog_core_init; | ||
3395 | } | ||
3396 | |||
3397 | spec->aloopback_mask = 0x20; | ||
3398 | spec->aloopback_shift = 0; | ||
3399 | |||
3400 | /* GPIO0 High = EAPD */ | ||
3401 | spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0x1; | ||
3402 | |||
3403 | spec->mux_nids = stac92hd71bxx_mux_nids; | ||
3404 | spec->adc_nids = stac92hd71bxx_adc_nids; | ||
3405 | spec->dmic_nids = stac92hd71bxx_dmic_nids; | ||
3406 | spec->dmux_nids = stac92hd71bxx_dmux_nids; | ||
3407 | |||
3408 | spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); | ||
3409 | spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); | ||
3410 | spec->num_dmics = STAC92HD71BXX_NUM_DMICS; | ||
3411 | spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); | ||
3412 | |||
3413 | spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); | ||
3414 | spec->pwr_nids = stac92hd71bxx_pwr_nids; | ||
3415 | |||
3416 | spec->multiout.num_dacs = 2; | ||
3417 | spec->multiout.hp_nid = 0x11; | ||
3418 | spec->multiout.dac_nids = stac92hd71bxx_dac_nids; | ||
3419 | |||
3420 | err = stac92xx_parse_auto_config(codec, 0x21, 0x23); | ||
3421 | if (!err) { | ||
3422 | if (spec->board_config < 0) { | ||
3423 | printk(KERN_WARNING "hda_codec: No auto-config is " | ||
3424 | "available, default to model=ref\n"); | ||
3425 | spec->board_config = STAC_92HD71BXX_REF; | ||
3426 | goto again; | ||
3427 | } | ||
3428 | err = -EINVAL; | ||
3429 | } | ||
3430 | |||
3431 | if (err < 0) { | ||
3432 | stac92xx_free(codec); | ||
3433 | return err; | ||
3434 | } | ||
3435 | |||
3436 | codec->patch_ops = stac92xx_patch_ops; | ||
3437 | |||
3438 | return 0; | ||
3439 | }; | ||
3440 | |||
2609 | static int patch_stac922x(struct hda_codec *codec) | 3441 | static int patch_stac922x(struct hda_codec *codec) |
2610 | { | 3442 | { |
2611 | struct sigmatel_spec *spec; | 3443 | struct sigmatel_spec *spec; |
@@ -2622,7 +3454,8 @@ static int patch_stac922x(struct hda_codec *codec) | |||
2622 | stac922x_models, | 3454 | stac922x_models, |
2623 | stac922x_cfg_tbl); | 3455 | stac922x_cfg_tbl); |
2624 | if (spec->board_config == STAC_INTEL_MAC_V3) { | 3456 | if (spec->board_config == STAC_INTEL_MAC_V3) { |
2625 | spec->gpio_mute = 1; | 3457 | spec->gpio_mask = spec->gpio_dir = 0x03; |
3458 | spec->gpio_data = 0x03; | ||
2626 | /* Intel Macs have all same PCI SSID, so we need to check | 3459 | /* Intel Macs have all same PCI SSID, so we need to check |
2627 | * codec SSID to distinguish the exact models | 3460 | * codec SSID to distinguish the exact models |
2628 | */ | 3461 | */ |
@@ -2675,6 +3508,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
2675 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); | 3508 | spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); |
2676 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); | 3509 | spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); |
2677 | spec->num_dmics = 0; | 3510 | spec->num_dmics = 0; |
3511 | spec->num_pwrs = 0; | ||
2678 | 3512 | ||
2679 | spec->init = stac922x_core_init; | 3513 | spec->init = stac922x_core_init; |
2680 | spec->mixer = stac922x_mixer; | 3514 | spec->mixer = stac922x_mixer; |
@@ -2724,53 +3558,70 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2724 | stac927x_models, | 3558 | stac927x_models, |
2725 | stac927x_cfg_tbl); | 3559 | stac927x_cfg_tbl); |
2726 | again: | 3560 | again: |
2727 | if (spec->board_config < 0) { | 3561 | if (spec->board_config < 0 || !stac927x_brd_tbl[spec->board_config]) { |
2728 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC927x, using BIOS defaults\n"); | 3562 | if (spec->board_config < 0) |
3563 | snd_printdd(KERN_INFO "hda_codec: Unknown model for" | ||
3564 | "STAC927x, using BIOS defaults\n"); | ||
2729 | err = stac92xx_save_bios_config_regs(codec); | 3565 | err = stac92xx_save_bios_config_regs(codec); |
2730 | if (err < 0) { | 3566 | if (err < 0) { |
2731 | stac92xx_free(codec); | 3567 | stac92xx_free(codec); |
2732 | return err; | 3568 | return err; |
2733 | } | 3569 | } |
2734 | spec->pin_configs = spec->bios_pin_configs; | 3570 | spec->pin_configs = spec->bios_pin_configs; |
2735 | } else if (stac927x_brd_tbl[spec->board_config] != NULL) { | 3571 | } else { |
2736 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; | 3572 | spec->pin_configs = stac927x_brd_tbl[spec->board_config]; |
2737 | stac92xx_set_config_regs(codec); | 3573 | stac92xx_set_config_regs(codec); |
2738 | } | 3574 | } |
2739 | 3575 | ||
3576 | spec->adc_nids = stac927x_adc_nids; | ||
3577 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
3578 | spec->mux_nids = stac927x_mux_nids; | ||
3579 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | ||
3580 | spec->multiout.dac_nids = spec->dac_nids; | ||
3581 | |||
2740 | switch (spec->board_config) { | 3582 | switch (spec->board_config) { |
2741 | case STAC_D965_3ST: | 3583 | case STAC_D965_3ST: |
2742 | spec->adc_nids = stac927x_adc_nids; | 3584 | case STAC_D965_5ST: |
2743 | spec->mux_nids = stac927x_mux_nids; | 3585 | /* GPIO0 High = Enable EAPD */ |
2744 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3586 | spec->gpio_mask = spec->gpio_dir = 0x01; |
2745 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | 3587 | spec->gpio_data = 0x01; |
2746 | spec->num_dmics = 0; | 3588 | spec->num_dmics = 0; |
3589 | |||
2747 | spec->init = d965_core_init; | 3590 | spec->init = d965_core_init; |
2748 | spec->mixer = stac927x_mixer; | 3591 | spec->mixer = stac927x_mixer; |
2749 | break; | 3592 | break; |
2750 | case STAC_D965_5ST: | 3593 | case STAC_DELL_BIOS: |
2751 | spec->adc_nids = stac927x_adc_nids; | 3594 | /* correct the front output jack as a hp out */ |
2752 | spec->mux_nids = stac927x_mux_nids; | 3595 | stac92xx_set_config_reg(codec, 0x0f, 0x02270110); |
2753 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3596 | /* correct the front input jack as a mic */ |
2754 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | 3597 | stac92xx_set_config_reg(codec, 0x0e, 0x02a79130); |
2755 | spec->num_dmics = 0; | 3598 | /* fallthru */ |
3599 | case STAC_DELL_3ST: | ||
3600 | /* GPIO2 High = Enable EAPD */ | ||
3601 | spec->gpio_mask = spec->gpio_dir = 0x04; | ||
3602 | spec->gpio_data = 0x04; | ||
3603 | spec->dmic_nids = stac927x_dmic_nids; | ||
3604 | spec->num_dmics = STAC927X_NUM_DMICS; | ||
3605 | |||
2756 | spec->init = d965_core_init; | 3606 | spec->init = d965_core_init; |
2757 | spec->mixer = stac927x_mixer; | 3607 | spec->mixer = stac927x_mixer; |
3608 | spec->dmux_nids = stac927x_dmux_nids; | ||
3609 | spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); | ||
2758 | break; | 3610 | break; |
2759 | default: | 3611 | default: |
2760 | spec->adc_nids = stac927x_adc_nids; | 3612 | /* GPIO0 High = Enable EAPD */ |
2761 | spec->mux_nids = stac927x_mux_nids; | 3613 | spec->gpio_mask = spec->gpio_dir = 0x1; |
2762 | spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); | 3614 | spec->gpio_data = 0x01; |
2763 | spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); | ||
2764 | spec->num_dmics = 0; | 3615 | spec->num_dmics = 0; |
3616 | |||
2765 | spec->init = stac927x_core_init; | 3617 | spec->init = stac927x_core_init; |
2766 | spec->mixer = stac927x_mixer; | 3618 | spec->mixer = stac927x_mixer; |
2767 | } | 3619 | } |
2768 | 3620 | ||
2769 | spec->multiout.dac_nids = spec->dac_nids; | 3621 | spec->num_pwrs = 0; |
2770 | /* GPIO0 High = Enable EAPD */ | 3622 | spec->aloopback_mask = 0x40; |
2771 | spec->gpio_mask = spec->gpio_data = 0x00000001; | 3623 | spec->aloopback_shift = 0; |
2772 | stac92xx_enable_gpio_mask(codec); | 3624 | |
2773 | |||
2774 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); | 3625 | err = stac92xx_parse_auto_config(codec, 0x1e, 0x20); |
2775 | if (!err) { | 3626 | if (!err) { |
2776 | if (spec->board_config < 0) { | 3627 | if (spec->board_config < 0) { |
@@ -2788,6 +3639,18 @@ static int patch_stac927x(struct hda_codec *codec) | |||
2788 | 3639 | ||
2789 | codec->patch_ops = stac92xx_patch_ops; | 3640 | codec->patch_ops = stac92xx_patch_ops; |
2790 | 3641 | ||
3642 | /* | ||
3643 | * !!FIXME!! | ||
3644 | * The STAC927x seem to require fairly long delays for certain | ||
3645 | * command sequences. With too short delays (even if the answer | ||
3646 | * is set to RIRB properly), it results in the silence output | ||
3647 | * on some hardwares like Dell. | ||
3648 | * | ||
3649 | * The below flag enables the longer delay (see get_response | ||
3650 | * in hda_intel.c). | ||
3651 | */ | ||
3652 | codec->bus->needs_damn_long_delay = 1; | ||
3653 | |||
2791 | return 0; | 3654 | return 0; |
2792 | } | 3655 | } |
2793 | 3656 | ||
@@ -2826,11 +3689,15 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2826 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); | 3689 | spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); |
2827 | spec->dmic_nids = stac9205_dmic_nids; | 3690 | spec->dmic_nids = stac9205_dmic_nids; |
2828 | spec->num_dmics = STAC9205_NUM_DMICS; | 3691 | spec->num_dmics = STAC9205_NUM_DMICS; |
2829 | spec->dmux_nid = 0x1d; | 3692 | spec->dmux_nids = stac9205_dmux_nids; |
3693 | spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); | ||
3694 | spec->num_pwrs = 0; | ||
2830 | 3695 | ||
2831 | spec->init = stac9205_core_init; | 3696 | spec->init = stac9205_core_init; |
2832 | spec->mixer = stac9205_mixer; | 3697 | spec->mixer = stac9205_mixer; |
2833 | 3698 | ||
3699 | spec->aloopback_mask = 0x40; | ||
3700 | spec->aloopback_shift = 0; | ||
2834 | spec->multiout.dac_nids = spec->dac_nids; | 3701 | spec->multiout.dac_nids = spec->dac_nids; |
2835 | 3702 | ||
2836 | switch (spec->board_config){ | 3703 | switch (spec->board_config){ |
@@ -2839,19 +3706,28 @@ static int patch_stac9205(struct hda_codec *codec) | |||
2839 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); | 3706 | stac92xx_set_config_reg(codec, 0x1f, 0x01441030); |
2840 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); | 3707 | stac92xx_set_config_reg(codec, 0x20, 0x1c410030); |
2841 | 3708 | ||
2842 | spec->gpio_mask = 0x00000007; /* GPIO0-2 */ | 3709 | /* Enable unsol response for GPIO4/Dock HP connection */ |
2843 | /* GPIO0 High = EAPD, GPIO1 Low = DRM, | 3710 | snd_hda_codec_write(codec, codec->afg, 0, |
2844 | * GPIO2 High = Headphone Mute | 3711 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); |
3712 | snd_hda_codec_write_cache(codec, codec->afg, 0, | ||
3713 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3714 | (AC_USRSP_EN | STAC_HP_EVENT)); | ||
3715 | |||
3716 | spec->gpio_dir = 0x0b; | ||
3717 | spec->gpio_mask = 0x1b; | ||
3718 | spec->gpio_mute = 0x10; | ||
3719 | /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, | ||
3720 | * GPIO3 Low = DRM | ||
2845 | */ | 3721 | */ |
2846 | spec->gpio_data = 0x00000005; | 3722 | spec->gpio_data = 0x01; |
2847 | break; | 3723 | break; |
2848 | default: | 3724 | default: |
2849 | /* GPIO0 High = EAPD */ | 3725 | /* GPIO0 High = EAPD */ |
2850 | spec->gpio_mask = spec->gpio_data = 0x00000001; | 3726 | spec->gpio_mask = spec->gpio_dir = 0x1; |
3727 | spec->gpio_data = 0x01; | ||
2851 | break; | 3728 | break; |
2852 | } | 3729 | } |
2853 | 3730 | ||
2854 | stac92xx_enable_gpio_mask(codec); | ||
2855 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); | 3731 | err = stac92xx_parse_auto_config(codec, 0x1f, 0x20); |
2856 | if (!err) { | 3732 | if (!err) { |
2857 | if (spec->board_config < 0) { | 3733 | if (spec->board_config < 0) { |
@@ -3005,7 +3881,7 @@ static int stac9872_vaio_init(struct hda_codec *codec) | |||
3005 | 3881 | ||
3006 | static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) | 3882 | static void stac9872_vaio_hp_detect(struct hda_codec *codec, unsigned int res) |
3007 | { | 3883 | { |
3008 | if (get_pin_presence(codec, 0x0a)) { | 3884 | if (get_hp_pin_presence(codec, 0x0a)) { |
3009 | stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); | 3885 | stac92xx_reset_pinctl(codec, 0x0f, AC_PINCTL_OUT_EN); |
3010 | stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); | 3886 | stac92xx_set_pinctl(codec, 0x0a, AC_PINCTL_OUT_EN); |
3011 | } else { | 3887 | } else { |
@@ -3087,6 +3963,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3087 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3963 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3088 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3964 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3089 | spec->adc_nids = vaio_adcs; | 3965 | spec->adc_nids = vaio_adcs; |
3966 | spec->num_pwrs = 0; | ||
3090 | spec->input_mux = &vaio_mux; | 3967 | spec->input_mux = &vaio_mux; |
3091 | spec->mux_nids = vaio_mux_nids; | 3968 | spec->mux_nids = vaio_mux_nids; |
3092 | codec->patch_ops = stac9872_vaio_patch_ops; | 3969 | codec->patch_ops = stac9872_vaio_patch_ops; |
@@ -3100,6 +3977,7 @@ static int patch_stac9872(struct hda_codec *codec) | |||
3100 | spec->multiout.dac_nids = vaio_dacs; | 3977 | spec->multiout.dac_nids = vaio_dacs; |
3101 | spec->multiout.hp_nid = VAIO_HP_DAC; | 3978 | spec->multiout.hp_nid = VAIO_HP_DAC; |
3102 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); | 3979 | spec->num_adcs = ARRAY_SIZE(vaio_adcs); |
3980 | spec->num_pwrs = 0; | ||
3103 | spec->adc_nids = vaio_adcs; | 3981 | spec->adc_nids = vaio_adcs; |
3104 | spec->input_mux = &vaio_mux; | 3982 | spec->input_mux = &vaio_mux; |
3105 | spec->mux_nids = vaio_mux_nids; | 3983 | spec->mux_nids = vaio_mux_nids; |
@@ -3159,5 +4037,17 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
3159 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, | 4037 | { .id = 0x838476a5, .name = "STAC9255D", .patch = patch_stac9205 }, |
3160 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, | 4038 | { .id = 0x838476a6, .name = "STAC9254", .patch = patch_stac9205 }, |
3161 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, | 4039 | { .id = 0x838476a7, .name = "STAC9254D", .patch = patch_stac9205 }, |
4040 | { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, | ||
4041 | { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, | ||
4042 | { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, | ||
4043 | { .id = 0x111d7608, .name = "92HD71BXX", .patch = patch_stac92hd71bxx }, | ||
4044 | { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | ||
4045 | { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, | ||
4046 | { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | ||
4047 | { .id = 0x111d76b3, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, | ||
4048 | { .id = 0x111d76b4, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, | ||
4049 | { .id = 0x111d76b5, .name = "92HD71B6X", .patch = patch_stac92hd71bxx }, | ||
4050 | { .id = 0x111d76b6, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | ||
4051 | { .id = 0x111d76b7, .name = "92HD71B5X", .patch = patch_stac92hd71bxx }, | ||
3162 | {} /* terminator */ | 4052 | {} /* terminator */ |
3163 | }; | 4053 | }; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4cdf3e6df4ba..4e5dd4cf36f5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -27,11 +27,12 @@ | |||
27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ | 27 | /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ |
28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ | 28 | /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ |
29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ | 29 | /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ |
30 | /* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ | ||
31 | /* 2007-09-17 Lydia Wang Add VT1708B codec support */ | ||
30 | /* */ | 32 | /* */ |
31 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | 33 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
32 | 34 | ||
33 | 35 | ||
34 | #include <sound/driver.h> | ||
35 | #include <linux/init.h> | 36 | #include <linux/init.h> |
36 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
37 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
@@ -51,14 +52,23 @@ | |||
51 | #define VT1708_HP_NID 0x13 | 52 | #define VT1708_HP_NID 0x13 |
52 | #define VT1708_DIGOUT_NID 0x14 | 53 | #define VT1708_DIGOUT_NID 0x14 |
53 | #define VT1708_DIGIN_NID 0x16 | 54 | #define VT1708_DIGIN_NID 0x16 |
55 | #define VT1708_DIGIN_PIN 0x26 | ||
54 | 56 | ||
55 | #define VT1709_HP_DAC_NID 0x28 | 57 | #define VT1709_HP_DAC_NID 0x28 |
56 | #define VT1709_DIGOUT_NID 0x13 | 58 | #define VT1709_DIGOUT_NID 0x13 |
57 | #define VT1709_DIGIN_NID 0x17 | 59 | #define VT1709_DIGIN_NID 0x17 |
60 | #define VT1709_DIGIN_PIN 0x25 | ||
61 | |||
62 | #define VT1708B_HP_NID 0x25 | ||
63 | #define VT1708B_DIGOUT_NID 0x12 | ||
64 | #define VT1708B_DIGIN_NID 0x15 | ||
65 | #define VT1708B_DIGIN_PIN 0x21 | ||
58 | 66 | ||
59 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) | 67 | #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) |
60 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) | 68 | #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) |
61 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) | 69 | #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) |
70 | #define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) | ||
71 | #define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) | ||
62 | 72 | ||
63 | 73 | ||
64 | enum { | 74 | enum { |
@@ -131,6 +141,11 @@ static hda_nid_t vt1709_adc_nids[3] = { | |||
131 | 0x14, 0x15, 0x16 | 141 | 0x14, 0x15, 0x16 |
132 | }; | 142 | }; |
133 | 143 | ||
144 | static hda_nid_t vt1708B_adc_nids[2] = { | ||
145 | /* ADC1-2 */ | ||
146 | 0x13, 0x14 | ||
147 | }; | ||
148 | |||
134 | /* add dynamic controls */ | 149 | /* add dynamic controls */ |
135 | static int via_add_control(struct via_spec *spec, int type, const char *name, | 150 | static int via_add_control(struct via_spec *spec, int type, const char *name, |
136 | unsigned long val) | 151 | unsigned long val) |
@@ -268,9 +283,13 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
268 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 283 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
269 | 0x18, &spec->cur_mux[adc_idx]); | 284 | 0x18, &spec->cur_mux[adc_idx]); |
270 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || | 285 | else if ((IS_VT1709_10CH_VENDORID(vendor_id) || |
271 | IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) | 286 | IS_VT1709_6CH_VENDORID(vendor_id)) && adc_idx == 0) |
272 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 287 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
273 | 0x19, &spec->cur_mux[adc_idx]); | 288 | 0x19, &spec->cur_mux[adc_idx]); |
289 | else if ((IS_VT1708B_8CH_VENDORID(vendor_id) || | ||
290 | IS_VT1708B_4CH_VENDORID(vendor_id)) && adc_idx == 0) | ||
291 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | ||
292 | 0x17, &spec->cur_mux[adc_idx]); | ||
274 | else | 293 | else |
275 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, | 294 | return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, |
276 | spec->adc_nids[adc_idx], | 295 | spec->adc_nids[adc_idx], |
@@ -287,7 +306,6 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = { | |||
287 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 306 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
288 | /* The multiple "Capture Source" controls confuse alsamixer | 307 | /* The multiple "Capture Source" controls confuse alsamixer |
289 | * So call somewhat different.. | 308 | * So call somewhat different.. |
290 | * FIXME: the controls appear in the "playback" view! | ||
291 | */ | 309 | */ |
292 | /* .name = "Capture Source", */ | 310 | /* .name = "Capture Source", */ |
293 | .name = "Input Source", | 311 | .name = "Input Source", |
@@ -309,15 +327,15 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
309 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 327 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
310 | 328 | ||
311 | 329 | ||
312 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 330 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
313 | * mixer widget | 331 | * mixer widget |
314 | */ | 332 | */ |
315 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 333 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
316 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* master */ | 334 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
317 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 335 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
318 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 336 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
319 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 337 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, |
320 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 338 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
321 | 339 | ||
322 | /* | 340 | /* |
323 | * Set up output mixers (0x19 - 0x1b) | 341 | * Set up output mixers (0x19 - 0x1b) |
@@ -329,10 +347,9 @@ static struct hda_verb vt1708_volume_init_verbs[] = { | |||
329 | 347 | ||
330 | /* Setup default input to PW4 */ | 348 | /* Setup default input to PW4 */ |
331 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 349 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, |
332 | /* Set mic as default input of sw0 */ | ||
333 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
334 | /* PW9 Output enable */ | 350 | /* PW9 Output enable */ |
335 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 351 | {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
352 | { } | ||
336 | }; | 353 | }; |
337 | 354 | ||
338 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, | 355 | static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -544,6 +561,33 @@ static int via_init(struct hda_codec *codec) | |||
544 | { | 561 | { |
545 | struct via_spec *spec = codec->spec; | 562 | struct via_spec *spec = codec->spec; |
546 | snd_hda_sequence_write(codec, spec->init_verbs); | 563 | snd_hda_sequence_write(codec, spec->init_verbs); |
564 | /* Lydia Add for EAPD enable */ | ||
565 | if (!spec->dig_in_nid) { /* No Digital In connection */ | ||
566 | if (IS_VT1708_VENDORID(codec->vendor_id)) { | ||
567 | snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0, | ||
568 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
569 | PIN_OUT); | ||
570 | snd_hda_codec_write(codec, VT1708_DIGIN_PIN, 0, | ||
571 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
572 | } else if (IS_VT1709_10CH_VENDORID(codec->vendor_id) || | ||
573 | IS_VT1709_6CH_VENDORID(codec->vendor_id)) { | ||
574 | snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0, | ||
575 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
576 | PIN_OUT); | ||
577 | snd_hda_codec_write(codec, VT1709_DIGIN_PIN, 0, | ||
578 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
579 | } else if (IS_VT1708B_8CH_VENDORID(codec->vendor_id) || | ||
580 | IS_VT1708B_4CH_VENDORID(codec->vendor_id)) { | ||
581 | snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0, | ||
582 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
583 | PIN_OUT); | ||
584 | snd_hda_codec_write(codec, VT1708B_DIGIN_PIN, 0, | ||
585 | AC_VERB_SET_EAPD_BTLENABLE, 0x02); | ||
586 | } | ||
587 | } else /* enable SPDIF-input pin */ | ||
588 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, | ||
589 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | ||
590 | |||
547 | return 0; | 591 | return 0; |
548 | } | 592 | } |
549 | 593 | ||
@@ -623,58 +667,68 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, | |||
623 | if (i == AUTO_SEQ_CENLFE) { | 667 | if (i == AUTO_SEQ_CENLFE) { |
624 | /* Center/LFE */ | 668 | /* Center/LFE */ |
625 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 669 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
626 | "Center Playback Volume", | 670 | "Center Playback Volume", |
627 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | 671 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
672 | HDA_OUTPUT)); | ||
628 | if (err < 0) | 673 | if (err < 0) |
629 | return err; | 674 | return err; |
630 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 675 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
631 | "LFE Playback Volume", | 676 | "LFE Playback Volume", |
632 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | 677 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
678 | HDA_OUTPUT)); | ||
633 | if (err < 0) | 679 | if (err < 0) |
634 | return err; | 680 | return err; |
635 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 681 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
636 | "Center Playback Switch", | 682 | "Center Playback Switch", |
637 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); | 683 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, |
684 | HDA_OUTPUT)); | ||
638 | if (err < 0) | 685 | if (err < 0) |
639 | return err; | 686 | return err; |
640 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 687 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
641 | "LFE Playback Switch", | 688 | "LFE Playback Switch", |
642 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); | 689 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, |
690 | HDA_OUTPUT)); | ||
643 | if (err < 0) | 691 | if (err < 0) |
644 | return err; | 692 | return err; |
645 | } else if (i == AUTO_SEQ_FRONT){ | 693 | } else if (i == AUTO_SEQ_FRONT){ |
646 | /* add control to mixer index 0 */ | 694 | /* add control to mixer index 0 */ |
647 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 695 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
648 | "Master Front Playback Volume", | 696 | "Master Front Playback Volume", |
649 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | 697 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, |
698 | HDA_INPUT)); | ||
650 | if (err < 0) | 699 | if (err < 0) |
651 | return err; | 700 | return err; |
652 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 701 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
653 | "Master Front Playback Switch", | 702 | "Master Front Playback Switch", |
654 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); | 703 | HDA_COMPOSE_AMP_VAL(0x17, 3, 0, |
704 | HDA_INPUT)); | ||
655 | if (err < 0) | 705 | if (err < 0) |
656 | return err; | 706 | return err; |
657 | 707 | ||
658 | /* add control to PW3 */ | 708 | /* add control to PW3 */ |
659 | sprintf(name, "%s Playback Volume", chname[i]); | 709 | sprintf(name, "%s Playback Volume", chname[i]); |
660 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 710 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
661 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 711 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
712 | HDA_OUTPUT)); | ||
662 | if (err < 0) | 713 | if (err < 0) |
663 | return err; | 714 | return err; |
664 | sprintf(name, "%s Playback Switch", chname[i]); | 715 | sprintf(name, "%s Playback Switch", chname[i]); |
665 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 716 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
666 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 717 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
718 | HDA_OUTPUT)); | ||
667 | if (err < 0) | 719 | if (err < 0) |
668 | return err; | 720 | return err; |
669 | } else { | 721 | } else { |
670 | sprintf(name, "%s Playback Volume", chname[i]); | 722 | sprintf(name, "%s Playback Volume", chname[i]); |
671 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 723 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
672 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | 724 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
725 | HDA_OUTPUT)); | ||
673 | if (err < 0) | 726 | if (err < 0) |
674 | return err; | 727 | return err; |
675 | sprintf(name, "%s Playback Switch", chname[i]); | 728 | sprintf(name, "%s Playback Switch", chname[i]); |
676 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 729 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
677 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); | 730 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, |
731 | HDA_OUTPUT)); | ||
678 | if (err < 0) | 732 | if (err < 0) |
679 | return err; | 733 | return err; |
680 | } | 734 | } |
@@ -875,7 +929,6 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { | |||
875 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 929 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
876 | /* The multiple "Capture Source" controls confuse alsamixer | 930 | /* The multiple "Capture Source" controls confuse alsamixer |
877 | * So call somewhat different.. | 931 | * So call somewhat different.. |
878 | * FIXME: the controls appear in the "playback" view! | ||
879 | */ | 932 | */ |
880 | /* .name = "Capture Source", */ | 933 | /* .name = "Capture Source", */ |
881 | .name = "Input Source", | 934 | .name = "Input Source", |
@@ -899,15 +952,15 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
899 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | 952 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
900 | 953 | ||
901 | 954 | ||
902 | /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | 955 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback |
903 | * mixer widget | 956 | * mixer widget |
904 | */ | 957 | */ |
905 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | 958 | /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ |
906 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* unmute master */ | 959 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, |
907 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | 960 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, |
908 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | 961 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, |
909 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | 962 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, |
910 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | 963 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, |
911 | 964 | ||
912 | /* | 965 | /* |
913 | * Set up output selector (0x1a, 0x1b, 0x29) | 966 | * Set up output selector (0x1a, 0x1b, 0x29) |
@@ -925,8 +978,6 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { | |||
925 | 978 | ||
926 | /* Set input of PW4 as AOW4 */ | 979 | /* Set input of PW4 as AOW4 */ |
927 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, | 980 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, |
928 | /* Set mic as default input of sw0 */ | ||
929 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
930 | /* PW9 Output enable */ | 981 | /* PW9 Output enable */ |
931 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 982 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
932 | { } | 983 | { } |
@@ -1073,68 +1124,80 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, | |||
1073 | /* Center/LFE */ | 1124 | /* Center/LFE */ |
1074 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1125 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1075 | "Center Playback Volume", | 1126 | "Center Playback Volume", |
1076 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | 1127 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, |
1128 | HDA_OUTPUT)); | ||
1077 | if (err < 0) | 1129 | if (err < 0) |
1078 | return err; | 1130 | return err; |
1079 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1131 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1080 | "LFE Playback Volume", | 1132 | "LFE Playback Volume", |
1081 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | 1133 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, |
1134 | HDA_OUTPUT)); | ||
1082 | if (err < 0) | 1135 | if (err < 0) |
1083 | return err; | 1136 | return err; |
1084 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1137 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1085 | "Center Playback Switch", | 1138 | "Center Playback Switch", |
1086 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); | 1139 | HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, |
1140 | HDA_OUTPUT)); | ||
1087 | if (err < 0) | 1141 | if (err < 0) |
1088 | return err; | 1142 | return err; |
1089 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1143 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1090 | "LFE Playback Switch", | 1144 | "LFE Playback Switch", |
1091 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); | 1145 | HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, |
1146 | HDA_OUTPUT)); | ||
1092 | if (err < 0) | 1147 | if (err < 0) |
1093 | return err; | 1148 | return err; |
1094 | } else if (i == AUTO_SEQ_FRONT){ | 1149 | } else if (i == AUTO_SEQ_FRONT){ |
1095 | /* add control to mixer index 0 */ | 1150 | /* add control to mixer index 0 */ |
1096 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | 1151 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, |
1097 | "Master Front Playback Volume", | 1152 | "Master Front Playback Volume", |
1098 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | 1153 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, |
1154 | HDA_INPUT)); | ||
1099 | if (err < 0) | 1155 | if (err < 0) |
1100 | return err; | 1156 | return err; |
1101 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | 1157 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, |
1102 | "Master Front Playback Switch", | 1158 | "Master Front Playback Switch", |
1103 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); | 1159 | HDA_COMPOSE_AMP_VAL(0x18, 3, 0, |
1160 | HDA_INPUT)); | ||
1104 | if (err < 0) | 1161 | if (err < 0) |
1105 | return err; | 1162 | return err; |
1106 | 1163 | ||
1107 | /* add control to PW3 */ | 1164 | /* add control to PW3 */ |
1108 | sprintf(name, "%s Playback Volume", chname[i]); | 1165 | sprintf(name, "%s Playback Volume", chname[i]); |
1109 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1166 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1110 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 1167 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
1168 | HDA_OUTPUT)); | ||
1111 | if (err < 0) | 1169 | if (err < 0) |
1112 | return err; | 1170 | return err; |
1113 | sprintf(name, "%s Playback Switch", chname[i]); | 1171 | sprintf(name, "%s Playback Switch", chname[i]); |
1114 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1172 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1115 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); | 1173 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, |
1174 | HDA_OUTPUT)); | ||
1116 | if (err < 0) | 1175 | if (err < 0) |
1117 | return err; | 1176 | return err; |
1118 | } else if (i == AUTO_SEQ_SURROUND) { | 1177 | } else if (i == AUTO_SEQ_SURROUND) { |
1119 | sprintf(name, "%s Playback Volume", chname[i]); | 1178 | sprintf(name, "%s Playback Volume", chname[i]); |
1120 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1179 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1121 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | 1180 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1181 | HDA_OUTPUT)); | ||
1122 | if (err < 0) | 1182 | if (err < 0) |
1123 | return err; | 1183 | return err; |
1124 | sprintf(name, "%s Playback Switch", chname[i]); | 1184 | sprintf(name, "%s Playback Switch", chname[i]); |
1125 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1185 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1126 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); | 1186 | HDA_COMPOSE_AMP_VAL(0x29, 3, 0, |
1187 | HDA_OUTPUT)); | ||
1127 | if (err < 0) | 1188 | if (err < 0) |
1128 | return err; | 1189 | return err; |
1129 | } else if (i == AUTO_SEQ_SIDE) { | 1190 | } else if (i == AUTO_SEQ_SIDE) { |
1130 | sprintf(name, "%s Playback Volume", chname[i]); | 1191 | sprintf(name, "%s Playback Volume", chname[i]); |
1131 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | 1192 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, |
1132 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | 1193 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1194 | HDA_OUTPUT)); | ||
1133 | if (err < 0) | 1195 | if (err < 0) |
1134 | return err; | 1196 | return err; |
1135 | sprintf(name, "%s Playback Switch", chname[i]); | 1197 | sprintf(name, "%s Playback Switch", chname[i]); |
1136 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | 1198 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, |
1137 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); | 1199 | HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, |
1200 | HDA_OUTPUT)); | ||
1138 | if (err < 0) | 1201 | if (err < 0) |
1139 | return err; | 1202 | return err; |
1140 | } | 1203 | } |
@@ -1351,8 +1414,6 @@ static struct hda_verb vt1709_6ch_volume_init_verbs[] = { | |||
1351 | 1414 | ||
1352 | /* Set input of PW4 as MW0 */ | 1415 | /* Set input of PW4 as MW0 */ |
1353 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, | 1416 | {0x20, AC_VERB_SET_CONNECT_SEL, 0}, |
1354 | /* Set mic as default input of sw0 */ | ||
1355 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, | ||
1356 | /* PW9 Output enable */ | 1417 | /* PW9 Output enable */ |
1357 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | 1418 | {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, |
1358 | { } | 1419 | { } |
@@ -1403,6 +1464,494 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
1403 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1464 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1404 | spec->loopback.amplist = vt1709_loopbacks; | 1465 | spec->loopback.amplist = vt1709_loopbacks; |
1405 | #endif | 1466 | #endif |
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | /* capture mixer elements */ | ||
1471 | static struct snd_kcontrol_new vt1708B_capture_mixer[] = { | ||
1472 | HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), | ||
1473 | HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), | ||
1474 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), | ||
1475 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), | ||
1476 | { | ||
1477 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1478 | /* The multiple "Capture Source" controls confuse alsamixer | ||
1479 | * So call somewhat different.. | ||
1480 | */ | ||
1481 | /* .name = "Capture Source", */ | ||
1482 | .name = "Input Source", | ||
1483 | .count = 1, | ||
1484 | .info = via_mux_enum_info, | ||
1485 | .get = via_mux_enum_get, | ||
1486 | .put = via_mux_enum_put, | ||
1487 | }, | ||
1488 | { } /* end */ | ||
1489 | }; | ||
1490 | /* | ||
1491 | * generic initialization of ADC, input mixers and output mixers | ||
1492 | */ | ||
1493 | static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { | ||
1494 | /* | ||
1495 | * Unmute ADC0-1 and set the default input to mic-in | ||
1496 | */ | ||
1497 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1498 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1499 | |||
1500 | |||
1501 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
1502 | * mixer widget | ||
1503 | */ | ||
1504 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
1505 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1506 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1507 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
1508 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
1509 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
1510 | |||
1511 | /* | ||
1512 | * Set up output mixers | ||
1513 | */ | ||
1514 | /* set vol=0 to output mixers */ | ||
1515 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1516 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1517 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1518 | |||
1519 | /* Setup default input to PW4 */ | ||
1520 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
1521 | /* PW9 Output enable */ | ||
1522 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1523 | /* PW10 Input enable */ | ||
1524 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1525 | { } | ||
1526 | }; | ||
1527 | |||
1528 | static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { | ||
1529 | /* | ||
1530 | * Unmute ADC0-1 and set the default input to mic-in | ||
1531 | */ | ||
1532 | {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1533 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1534 | |||
1535 | |||
1536 | /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback | ||
1537 | * mixer widget | ||
1538 | */ | ||
1539 | /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ | ||
1540 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
1541 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
1542 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, | ||
1543 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, | ||
1544 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, | ||
1545 | |||
1546 | /* | ||
1547 | * Set up output mixers | ||
1548 | */ | ||
1549 | /* set vol=0 to output mixers */ | ||
1550 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1551 | {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1552 | {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
1553 | |||
1554 | /* Setup default input of PW4 to MW0 */ | ||
1555 | {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1556 | /* PW9 Output enable */ | ||
1557 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, | ||
1558 | /* PW10 Input enable */ | ||
1559 | {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | ||
1560 | { } | ||
1561 | }; | ||
1562 | |||
1563 | static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { | ||
1564 | .substreams = 1, | ||
1565 | .channels_min = 2, | ||
1566 | .channels_max = 8, | ||
1567 | .nid = 0x10, /* NID to query formats and rates */ | ||
1568 | .ops = { | ||
1569 | .open = via_playback_pcm_open, | ||
1570 | .prepare = via_playback_pcm_prepare, | ||
1571 | .cleanup = via_playback_pcm_cleanup | ||
1572 | }, | ||
1573 | }; | ||
1574 | |||
1575 | static struct hda_pcm_stream vt1708B_4ch_pcm_analog_playback = { | ||
1576 | .substreams = 1, | ||
1577 | .channels_min = 2, | ||
1578 | .channels_max = 4, | ||
1579 | .nid = 0x10, /* NID to query formats and rates */ | ||
1580 | .ops = { | ||
1581 | .open = via_playback_pcm_open, | ||
1582 | .prepare = via_playback_pcm_prepare, | ||
1583 | .cleanup = via_playback_pcm_cleanup | ||
1584 | }, | ||
1585 | }; | ||
1586 | |||
1587 | static struct hda_pcm_stream vt1708B_pcm_analog_capture = { | ||
1588 | .substreams = 2, | ||
1589 | .channels_min = 2, | ||
1590 | .channels_max = 2, | ||
1591 | .nid = 0x13, /* NID to query formats and rates */ | ||
1592 | .ops = { | ||
1593 | .prepare = via_capture_pcm_prepare, | ||
1594 | .cleanup = via_capture_pcm_cleanup | ||
1595 | }, | ||
1596 | }; | ||
1597 | |||
1598 | static struct hda_pcm_stream vt1708B_pcm_digital_playback = { | ||
1599 | .substreams = 1, | ||
1600 | .channels_min = 2, | ||
1601 | .channels_max = 2, | ||
1602 | /* NID is set in via_build_pcms */ | ||
1603 | .ops = { | ||
1604 | .open = via_dig_playback_pcm_open, | ||
1605 | .close = via_dig_playback_pcm_close, | ||
1606 | .prepare = via_dig_playback_pcm_prepare | ||
1607 | }, | ||
1608 | }; | ||
1609 | |||
1610 | static struct hda_pcm_stream vt1708B_pcm_digital_capture = { | ||
1611 | .substreams = 1, | ||
1612 | .channels_min = 2, | ||
1613 | .channels_max = 2, | ||
1614 | }; | ||
1615 | |||
1616 | /* fill in the dac_nids table from the parsed pin configuration */ | ||
1617 | static int vt1708B_auto_fill_dac_nids(struct via_spec *spec, | ||
1618 | const struct auto_pin_cfg *cfg) | ||
1619 | { | ||
1620 | int i; | ||
1621 | hda_nid_t nid; | ||
1622 | |||
1623 | spec->multiout.num_dacs = cfg->line_outs; | ||
1624 | |||
1625 | spec->multiout.dac_nids = spec->private_dac_nids; | ||
1626 | |||
1627 | for (i = 0; i < 4; i++) { | ||
1628 | nid = cfg->line_out_pins[i]; | ||
1629 | if (nid) { | ||
1630 | /* config dac list */ | ||
1631 | switch (i) { | ||
1632 | case AUTO_SEQ_FRONT: | ||
1633 | spec->multiout.dac_nids[i] = 0x10; | ||
1634 | break; | ||
1635 | case AUTO_SEQ_CENLFE: | ||
1636 | spec->multiout.dac_nids[i] = 0x24; | ||
1637 | break; | ||
1638 | case AUTO_SEQ_SURROUND: | ||
1639 | spec->multiout.dac_nids[i] = 0x25; | ||
1640 | break; | ||
1641 | case AUTO_SEQ_SIDE: | ||
1642 | spec->multiout.dac_nids[i] = 0x11; | ||
1643 | break; | ||
1644 | } | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | return 0; | ||
1649 | } | ||
1650 | |||
1651 | /* add playback controls from the parsed DAC table */ | ||
1652 | static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, | ||
1653 | const struct auto_pin_cfg *cfg) | ||
1654 | { | ||
1655 | char name[32]; | ||
1656 | static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; | ||
1657 | hda_nid_t nid_vols[] = {0x16, 0x27, 0x26, 0x18}; | ||
1658 | hda_nid_t nid, nid_vol = 0; | ||
1659 | int i, err; | ||
1660 | |||
1661 | for (i = 0; i <= AUTO_SEQ_SIDE; i++) { | ||
1662 | nid = cfg->line_out_pins[i]; | ||
1663 | |||
1664 | if (!nid) | ||
1665 | continue; | ||
1666 | |||
1667 | nid_vol = nid_vols[i]; | ||
1668 | |||
1669 | if (i == AUTO_SEQ_CENLFE) { | ||
1670 | /* Center/LFE */ | ||
1671 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1672 | "Center Playback Volume", | ||
1673 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
1674 | HDA_OUTPUT)); | ||
1675 | if (err < 0) | ||
1676 | return err; | ||
1677 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1678 | "LFE Playback Volume", | ||
1679 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
1680 | HDA_OUTPUT)); | ||
1681 | if (err < 0) | ||
1682 | return err; | ||
1683 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1684 | "Center Playback Switch", | ||
1685 | HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, | ||
1686 | HDA_OUTPUT)); | ||
1687 | if (err < 0) | ||
1688 | return err; | ||
1689 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1690 | "LFE Playback Switch", | ||
1691 | HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, | ||
1692 | HDA_OUTPUT)); | ||
1693 | if (err < 0) | ||
1694 | return err; | ||
1695 | } else if (i == AUTO_SEQ_FRONT) { | ||
1696 | /* add control to mixer index 0 */ | ||
1697 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1698 | "Master Front Playback Volume", | ||
1699 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1700 | HDA_INPUT)); | ||
1701 | if (err < 0) | ||
1702 | return err; | ||
1703 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1704 | "Master Front Playback Switch", | ||
1705 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1706 | HDA_INPUT)); | ||
1707 | if (err < 0) | ||
1708 | return err; | ||
1709 | |||
1710 | /* add control to PW3 */ | ||
1711 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1712 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1713 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
1714 | HDA_OUTPUT)); | ||
1715 | if (err < 0) | ||
1716 | return err; | ||
1717 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1718 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1719 | HDA_COMPOSE_AMP_VAL(nid, 3, 0, | ||
1720 | HDA_OUTPUT)); | ||
1721 | if (err < 0) | ||
1722 | return err; | ||
1723 | } else { | ||
1724 | sprintf(name, "%s Playback Volume", chname[i]); | ||
1725 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, | ||
1726 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1727 | HDA_OUTPUT)); | ||
1728 | if (err < 0) | ||
1729 | return err; | ||
1730 | sprintf(name, "%s Playback Switch", chname[i]); | ||
1731 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, | ||
1732 | HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, | ||
1733 | HDA_OUTPUT)); | ||
1734 | if (err < 0) | ||
1735 | return err; | ||
1736 | } | ||
1737 | } | ||
1738 | |||
1739 | return 0; | ||
1740 | } | ||
1741 | |||
1742 | static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) | ||
1743 | { | ||
1744 | int err; | ||
1745 | |||
1746 | if (!pin) | ||
1747 | return 0; | ||
1748 | |||
1749 | spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ | ||
1750 | |||
1751 | err = via_add_control(spec, VIA_CTL_WIDGET_VOL, | ||
1752 | "Headphone Playback Volume", | ||
1753 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1754 | if (err < 0) | ||
1755 | return err; | ||
1756 | err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, | ||
1757 | "Headphone Playback Switch", | ||
1758 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); | ||
1759 | if (err < 0) | ||
1760 | return err; | ||
1761 | |||
1762 | return 0; | ||
1763 | } | ||
1764 | |||
1765 | /* create playback/capture controls for input pins */ | ||
1766 | static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, | ||
1767 | const struct auto_pin_cfg *cfg) | ||
1768 | { | ||
1769 | static char *labels[] = { | ||
1770 | "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL | ||
1771 | }; | ||
1772 | struct hda_input_mux *imux = &spec->private_imux; | ||
1773 | int i, err, idx = 0; | ||
1774 | |||
1775 | /* for internal loopback recording select */ | ||
1776 | imux->items[imux->num_items].label = "Stereo Mixer"; | ||
1777 | imux->items[imux->num_items].index = idx; | ||
1778 | imux->num_items++; | ||
1779 | |||
1780 | for (i = 0; i < AUTO_PIN_LAST; i++) { | ||
1781 | if (!cfg->input_pins[i]) | ||
1782 | continue; | ||
1783 | |||
1784 | switch (cfg->input_pins[i]) { | ||
1785 | case 0x1a: /* Mic */ | ||
1786 | idx = 2; | ||
1787 | break; | ||
1788 | |||
1789 | case 0x1b: /* Line In */ | ||
1790 | idx = 3; | ||
1791 | break; | ||
1792 | |||
1793 | case 0x1e: /* Front Mic */ | ||
1794 | idx = 4; | ||
1795 | break; | ||
1796 | |||
1797 | case 0x1f: /* CD */ | ||
1798 | idx = 1; | ||
1799 | break; | ||
1800 | } | ||
1801 | err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], | ||
1802 | idx, 0x16); | ||
1803 | if (err < 0) | ||
1804 | return err; | ||
1805 | imux->items[imux->num_items].label = labels[i]; | ||
1806 | imux->items[imux->num_items].index = idx; | ||
1807 | imux->num_items++; | ||
1808 | } | ||
1809 | return 0; | ||
1810 | } | ||
1811 | |||
1812 | static int vt1708B_parse_auto_config(struct hda_codec *codec) | ||
1813 | { | ||
1814 | struct via_spec *spec = codec->spec; | ||
1815 | int err; | ||
1816 | |||
1817 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
1818 | if (err < 0) | ||
1819 | return err; | ||
1820 | err = vt1708B_auto_fill_dac_nids(spec, &spec->autocfg); | ||
1821 | if (err < 0) | ||
1822 | return err; | ||
1823 | if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) | ||
1824 | return 0; /* can't find valid BIOS pin config */ | ||
1825 | |||
1826 | err = vt1708B_auto_create_multi_out_ctls(spec, &spec->autocfg); | ||
1827 | if (err < 0) | ||
1828 | return err; | ||
1829 | err = vt1708B_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); | ||
1830 | if (err < 0) | ||
1831 | return err; | ||
1832 | err = vt1708B_auto_create_analog_input_ctls(spec, &spec->autocfg); | ||
1833 | if (err < 0) | ||
1834 | return err; | ||
1835 | |||
1836 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | ||
1837 | |||
1838 | if (spec->autocfg.dig_out_pin) | ||
1839 | spec->multiout.dig_out_nid = VT1708B_DIGOUT_NID; | ||
1840 | if (spec->autocfg.dig_in_pin) | ||
1841 | spec->dig_in_nid = VT1708B_DIGIN_NID; | ||
1842 | |||
1843 | if (spec->kctl_alloc) | ||
1844 | spec->mixers[spec->num_mixers++] = spec->kctl_alloc; | ||
1845 | |||
1846 | spec->input_mux = &spec->private_imux; | ||
1847 | |||
1848 | return 1; | ||
1849 | } | ||
1850 | |||
1851 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1852 | static struct hda_amp_list vt1708B_loopbacks[] = { | ||
1853 | { 0x16, HDA_INPUT, 1 }, | ||
1854 | { 0x16, HDA_INPUT, 2 }, | ||
1855 | { 0x16, HDA_INPUT, 3 }, | ||
1856 | { 0x16, HDA_INPUT, 4 }, | ||
1857 | { } /* end */ | ||
1858 | }; | ||
1859 | #endif | ||
1860 | |||
1861 | static int patch_vt1708B_8ch(struct hda_codec *codec) | ||
1862 | { | ||
1863 | struct via_spec *spec; | ||
1864 | int err; | ||
1865 | |||
1866 | /* create a codec specific record */ | ||
1867 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1868 | if (spec == NULL) | ||
1869 | return -ENOMEM; | ||
1870 | |||
1871 | codec->spec = spec; | ||
1872 | |||
1873 | /* automatic parse from the BIOS config */ | ||
1874 | err = vt1708B_parse_auto_config(codec); | ||
1875 | if (err < 0) { | ||
1876 | via_free(codec); | ||
1877 | return err; | ||
1878 | } else if (!err) { | ||
1879 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
1880 | "from BIOS. Using genenic mode...\n"); | ||
1881 | } | ||
1882 | |||
1883 | spec->init_verbs = vt1708B_8ch_volume_init_verbs; | ||
1884 | |||
1885 | spec->stream_name_analog = "VT1708B Analog"; | ||
1886 | spec->stream_analog_playback = &vt1708B_8ch_pcm_analog_playback; | ||
1887 | spec->stream_analog_capture = &vt1708B_pcm_analog_capture; | ||
1888 | |||
1889 | spec->stream_name_digital = "VT1708B Digital"; | ||
1890 | spec->stream_digital_playback = &vt1708B_pcm_digital_playback; | ||
1891 | spec->stream_digital_capture = &vt1708B_pcm_digital_capture; | ||
1892 | |||
1893 | if (!spec->adc_nids && spec->input_mux) { | ||
1894 | spec->adc_nids = vt1708B_adc_nids; | ||
1895 | spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); | ||
1896 | spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; | ||
1897 | spec->num_mixers++; | ||
1898 | } | ||
1899 | |||
1900 | codec->patch_ops = via_patch_ops; | ||
1901 | |||
1902 | codec->patch_ops.init = via_auto_init; | ||
1903 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1904 | spec->loopback.amplist = vt1708B_loopbacks; | ||
1905 | #endif | ||
1906 | |||
1907 | return 0; | ||
1908 | } | ||
1909 | |||
1910 | static int patch_vt1708B_4ch(struct hda_codec *codec) | ||
1911 | { | ||
1912 | struct via_spec *spec; | ||
1913 | int err; | ||
1914 | |||
1915 | /* create a codec specific record */ | ||
1916 | spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); | ||
1917 | if (spec == NULL) | ||
1918 | return -ENOMEM; | ||
1919 | |||
1920 | codec->spec = spec; | ||
1921 | |||
1922 | /* automatic parse from the BIOS config */ | ||
1923 | err = vt1708B_parse_auto_config(codec); | ||
1924 | if (err < 0) { | ||
1925 | via_free(codec); | ||
1926 | return err; | ||
1927 | } else if (!err) { | ||
1928 | printk(KERN_INFO "hda_codec: Cannot set up configuration " | ||
1929 | "from BIOS. Using genenic mode...\n"); | ||
1930 | } | ||
1931 | |||
1932 | spec->init_verbs = vt1708B_4ch_volume_init_verbs; | ||
1933 | |||
1934 | spec->stream_name_analog = "VT1708B Analog"; | ||
1935 | spec->stream_analog_playback = &vt1708B_4ch_pcm_analog_playback; | ||
1936 | spec->stream_analog_capture = &vt1708B_pcm_analog_capture; | ||
1937 | |||
1938 | spec->stream_name_digital = "VT1708B Digital"; | ||
1939 | spec->stream_digital_playback = &vt1708B_pcm_digital_playback; | ||
1940 | spec->stream_digital_capture = &vt1708B_pcm_digital_capture; | ||
1941 | |||
1942 | if (!spec->adc_nids && spec->input_mux) { | ||
1943 | spec->adc_nids = vt1708B_adc_nids; | ||
1944 | spec->num_adc_nids = ARRAY_SIZE(vt1708B_adc_nids); | ||
1945 | spec->mixers[spec->num_mixers] = vt1708B_capture_mixer; | ||
1946 | spec->num_mixers++; | ||
1947 | } | ||
1948 | |||
1949 | codec->patch_ops = via_patch_ops; | ||
1950 | |||
1951 | codec->patch_ops.init = via_auto_init; | ||
1952 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1953 | spec->loopback.amplist = vt1708B_loopbacks; | ||
1954 | #endif | ||
1406 | 1955 | ||
1407 | return 0; | 1956 | return 0; |
1408 | } | 1957 | } |
@@ -1415,13 +1964,37 @@ struct hda_codec_preset snd_hda_preset_via[] = { | |||
1415 | { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, | 1964 | { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, |
1416 | { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, | 1965 | { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, |
1417 | { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, | 1966 | { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, |
1418 | { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1967 | { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", |
1419 | { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1968 | .patch = patch_vt1709_10ch}, |
1420 | { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1969 | { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", |
1421 | { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, | 1970 | .patch = patch_vt1709_10ch}, |
1422 | { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1971 | { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", |
1423 | { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1972 | .patch = patch_vt1709_10ch}, |
1424 | { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1973 | { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", |
1425 | { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, | 1974 | .patch = patch_vt1709_10ch}, |
1975 | { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", | ||
1976 | .patch = patch_vt1709_6ch}, | ||
1977 | { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", | ||
1978 | .patch = patch_vt1709_6ch}, | ||
1979 | { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", | ||
1980 | .patch = patch_vt1709_6ch}, | ||
1981 | { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", | ||
1982 | .patch = patch_vt1709_6ch}, | ||
1983 | { .id = 0x1106E720, .name = "VIA VT1708B 8-Ch", | ||
1984 | .patch = patch_vt1708B_8ch}, | ||
1985 | { .id = 0x1106E721, .name = "VIA VT1708B 8-Ch", | ||
1986 | .patch = patch_vt1708B_8ch}, | ||
1987 | { .id = 0x1106E722, .name = "VIA VT1708B 8-Ch", | ||
1988 | .patch = patch_vt1708B_8ch}, | ||
1989 | { .id = 0x1106E723, .name = "VIA VT1708B 8-Ch", | ||
1990 | .patch = patch_vt1708B_8ch}, | ||
1991 | { .id = 0x1106E724, .name = "VIA VT1708B 4-Ch", | ||
1992 | .patch = patch_vt1708B_4ch}, | ||
1993 | { .id = 0x1106E725, .name = "VIA VT1708B 4-Ch", | ||
1994 | .patch = patch_vt1708B_4ch}, | ||
1995 | { .id = 0x1106E726, .name = "VIA VT1708B 4-Ch", | ||
1996 | .patch = patch_vt1708B_4ch}, | ||
1997 | { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", | ||
1998 | .patch = patch_vt1708B_4ch}, | ||
1426 | {} /* terminator */ | 1999 | {} /* terminator */ |
1427 | }; | 2000 | }; |
diff --git a/sound/pci/hda/vmaster.c b/sound/pci/hda/vmaster.c new file mode 100644 index 000000000000..2da49d20a1fc --- /dev/null +++ b/sound/pci/hda/vmaster.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Virtual master and slave controls | ||
3 | * | ||
4 | * Copyright (c) 2008 by Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation, version 2. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/control.h> | ||
15 | |||
16 | /* | ||
17 | * a subset of information returned via ctl info callback | ||
18 | */ | ||
19 | struct link_ctl_info { | ||
20 | int type; /* value type */ | ||
21 | int count; /* item count */ | ||
22 | int min_val, max_val; /* min, max values */ | ||
23 | }; | ||
24 | |||
25 | /* | ||
26 | * link master - this contains a list of slave controls that are | ||
27 | * identical types, i.e. info returns the same value type and value | ||
28 | * ranges, but may have different number of counts. | ||
29 | * | ||
30 | * The master control is so far only mono volume/switch for simplicity. | ||
31 | * The same value will be applied to all slaves. | ||
32 | */ | ||
33 | struct link_master { | ||
34 | struct list_head slaves; | ||
35 | struct link_ctl_info info; | ||
36 | int val; /* the master value */ | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * link slave - this contains a slave control element | ||
41 | * | ||
42 | * It fakes the control callbacsk with additional attenuation by the | ||
43 | * master control. A slave may have either one or two channels. | ||
44 | */ | ||
45 | |||
46 | struct link_slave { | ||
47 | struct list_head list; | ||
48 | struct link_master *master; | ||
49 | struct link_ctl_info info; | ||
50 | int vals[2]; /* current values */ | ||
51 | struct snd_kcontrol slave; /* the copy of original control entry */ | ||
52 | }; | ||
53 | |||
54 | /* get the slave ctl info and save the initial values */ | ||
55 | static int slave_init(struct link_slave *slave) | ||
56 | { | ||
57 | struct snd_ctl_elem_info *uinfo; | ||
58 | struct snd_ctl_elem_value *uctl; | ||
59 | int err, ch; | ||
60 | |||
61 | if (slave->info.count) | ||
62 | return 0; /* already initialized */ | ||
63 | |||
64 | uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL); | ||
65 | if (!uinfo) | ||
66 | return -ENOMEM; | ||
67 | uinfo->id = slave->slave.id; | ||
68 | err = slave->slave.info(&slave->slave, uinfo); | ||
69 | if (err < 0) { | ||
70 | kfree(uinfo); | ||
71 | return err; | ||
72 | } | ||
73 | slave->info.type = uinfo->type; | ||
74 | slave->info.count = uinfo->count; | ||
75 | if (slave->info.count > 2 || | ||
76 | (slave->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER && | ||
77 | slave->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) { | ||
78 | snd_printk(KERN_ERR "invalid slave element\n"); | ||
79 | kfree(uinfo); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | slave->info.min_val = uinfo->value.integer.min; | ||
83 | slave->info.max_val = uinfo->value.integer.max; | ||
84 | kfree(uinfo); | ||
85 | |||
86 | uctl = kmalloc(sizeof(*uctl), GFP_KERNEL); | ||
87 | if (!uctl) | ||
88 | return -ENOMEM; | ||
89 | uctl->id = slave->slave.id; | ||
90 | err = slave->slave.get(&slave->slave, uctl); | ||
91 | for (ch = 0; ch < slave->info.count; ch++) | ||
92 | slave->vals[ch] = uctl->value.integer.value[ch]; | ||
93 | kfree(uctl); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* initialize master volume */ | ||
98 | static int master_init(struct link_master *master) | ||
99 | { | ||
100 | struct link_slave *slave; | ||
101 | |||
102 | if (master->info.count) | ||
103 | return 0; /* already initialized */ | ||
104 | |||
105 | list_for_each_entry(slave, &master->slaves, list) { | ||
106 | int err = slave_init(slave); | ||
107 | if (err < 0) | ||
108 | return err; | ||
109 | master->info = slave->info; | ||
110 | master->info.count = 1; /* always mono */ | ||
111 | /* set full volume as default (= no attenuation) */ | ||
112 | master->val = master->info.max_val; | ||
113 | return 0; | ||
114 | } | ||
115 | return -ENOENT; | ||
116 | } | ||
117 | |||
118 | static int slave_get_val(struct link_slave *slave, | ||
119 | struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | int err, ch; | ||
122 | |||
123 | err = slave_init(slave); | ||
124 | if (err < 0) | ||
125 | return err; | ||
126 | for (ch = 0; ch < slave->info.count; ch++) | ||
127 | ucontrol->value.integer.value[ch] = slave->vals[ch]; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int slave_put_val(struct link_slave *slave, | ||
132 | struct snd_ctl_elem_value *ucontrol) | ||
133 | { | ||
134 | int err, ch, vol; | ||
135 | |||
136 | err = master_init(slave->master); | ||
137 | if (err < 0) | ||
138 | return err; | ||
139 | |||
140 | switch (slave->info.type) { | ||
141 | case SNDRV_CTL_ELEM_TYPE_BOOLEAN: | ||
142 | for (ch = 0; ch < slave->info.count; ch++) | ||
143 | ucontrol->value.integer.value[ch] &= | ||
144 | !!slave->master->val; | ||
145 | break; | ||
146 | case SNDRV_CTL_ELEM_TYPE_INTEGER: | ||
147 | for (ch = 0; ch < slave->info.count; ch++) { | ||
148 | /* max master volume is supposed to be 0 dB */ | ||
149 | vol = ucontrol->value.integer.value[ch]; | ||
150 | vol += slave->master->val - slave->master->info.max_val; | ||
151 | if (vol < slave->info.min_val) | ||
152 | vol = slave->info.min_val; | ||
153 | else if (vol > slave->info.max_val) | ||
154 | vol = slave->info.max_val; | ||
155 | ucontrol->value.integer.value[ch] = vol; | ||
156 | } | ||
157 | break; | ||
158 | } | ||
159 | return slave->slave.put(&slave->slave, ucontrol); | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * ctl callbacks for slaves | ||
164 | */ | ||
165 | static int slave_info(struct snd_kcontrol *kcontrol, | ||
166 | struct snd_ctl_elem_info *uinfo) | ||
167 | { | ||
168 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
169 | return slave->slave.info(&slave->slave, uinfo); | ||
170 | } | ||
171 | |||
172 | static int slave_get(struct snd_kcontrol *kcontrol, | ||
173 | struct snd_ctl_elem_value *ucontrol) | ||
174 | { | ||
175 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
176 | return slave_get_val(slave, ucontrol); | ||
177 | } | ||
178 | |||
179 | static int slave_put(struct snd_kcontrol *kcontrol, | ||
180 | struct snd_ctl_elem_value *ucontrol) | ||
181 | { | ||
182 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
183 | int err, ch, changed = 0; | ||
184 | |||
185 | err = slave_init(slave); | ||
186 | if (err < 0) | ||
187 | return err; | ||
188 | for (ch = 0; ch < slave->info.count; ch++) { | ||
189 | if (slave->vals[ch] != ucontrol->value.integer.value[ch]) { | ||
190 | changed = 1; | ||
191 | slave->vals[ch] = ucontrol->value.integer.value[ch]; | ||
192 | } | ||
193 | } | ||
194 | if (!changed) | ||
195 | return 0; | ||
196 | return slave_put_val(slave, ucontrol); | ||
197 | } | ||
198 | |||
199 | static int slave_tlv_cmd(struct snd_kcontrol *kcontrol, | ||
200 | int op_flag, unsigned int size, | ||
201 | unsigned int __user *tlv) | ||
202 | { | ||
203 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
204 | /* FIXME: this assumes that the max volume is 0 dB */ | ||
205 | return slave->slave.tlv.c(&slave->slave, op_flag, size, tlv); | ||
206 | } | ||
207 | |||
208 | static void slave_free(struct snd_kcontrol *kcontrol) | ||
209 | { | ||
210 | struct link_slave *slave = snd_kcontrol_chip(kcontrol); | ||
211 | if (slave->slave.private_free) | ||
212 | slave->slave.private_free(&slave->slave); | ||
213 | if (slave->master) | ||
214 | list_del(&slave->list); | ||
215 | kfree(slave); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * Add a slave control to the group with the given master control | ||
220 | * | ||
221 | * All slaves must be the same type (returning the same information | ||
222 | * via info callback). The fucntion doesn't check it, so it's your | ||
223 | * responsibility. | ||
224 | * | ||
225 | * Also, some additional limitations: | ||
226 | * - at most two channels | ||
227 | * - logarithmic volume control (dB level), no linear volume | ||
228 | * - master can only attenuate the volume, no gain | ||
229 | */ | ||
230 | int snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave) | ||
231 | { | ||
232 | struct link_master *master_link = snd_kcontrol_chip(master); | ||
233 | struct link_slave *srec; | ||
234 | |||
235 | srec = kzalloc(sizeof(*srec) + | ||
236 | slave->count * sizeof(*slave->vd), GFP_KERNEL); | ||
237 | if (!srec) | ||
238 | return -ENOMEM; | ||
239 | srec->slave = *slave; | ||
240 | memcpy(srec->slave.vd, slave->vd, slave->count * sizeof(*slave->vd)); | ||
241 | srec->master = master_link; | ||
242 | |||
243 | /* override callbacks */ | ||
244 | slave->info = slave_info; | ||
245 | slave->get = slave_get; | ||
246 | slave->put = slave_put; | ||
247 | if (slave->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) | ||
248 | slave->tlv.c = slave_tlv_cmd; | ||
249 | slave->private_data = srec; | ||
250 | slave->private_free = slave_free; | ||
251 | |||
252 | list_add_tail(&srec->list, &master_link->slaves); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * ctl callbacks for master controls | ||
258 | */ | ||
259 | static int master_info(struct snd_kcontrol *kcontrol, | ||
260 | struct snd_ctl_elem_info *uinfo) | ||
261 | { | ||
262 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
263 | int ret; | ||
264 | |||
265 | ret = master_init(master); | ||
266 | if (ret < 0) | ||
267 | return ret; | ||
268 | uinfo->type = master->info.type; | ||
269 | uinfo->count = master->info.count; | ||
270 | uinfo->value.integer.min = master->info.min_val; | ||
271 | uinfo->value.integer.max = master->info.max_val; | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int master_get(struct snd_kcontrol *kcontrol, | ||
276 | struct snd_ctl_elem_value *ucontrol) | ||
277 | { | ||
278 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
279 | int err = master_init(master); | ||
280 | if (err < 0) | ||
281 | return err; | ||
282 | ucontrol->value.integer.value[0] = master->val; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int master_put(struct snd_kcontrol *kcontrol, | ||
287 | struct snd_ctl_elem_value *ucontrol) | ||
288 | { | ||
289 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
290 | struct link_slave *slave; | ||
291 | struct snd_ctl_elem_value *uval; | ||
292 | int err, old_val; | ||
293 | |||
294 | err = master_init(master); | ||
295 | if (err < 0) | ||
296 | return err; | ||
297 | old_val = master->val; | ||
298 | if (ucontrol->value.integer.value[0] == old_val) | ||
299 | return 0; | ||
300 | |||
301 | uval = kmalloc(sizeof(*uval), GFP_KERNEL); | ||
302 | if (!uval) | ||
303 | return -ENOMEM; | ||
304 | list_for_each_entry(slave, &master->slaves, list) { | ||
305 | master->val = old_val; | ||
306 | uval->id = slave->slave.id; | ||
307 | slave_get_val(slave, uval); | ||
308 | master->val = ucontrol->value.integer.value[0]; | ||
309 | slave_put_val(slave, uval); | ||
310 | } | ||
311 | kfree(uval); | ||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | static void master_free(struct snd_kcontrol *kcontrol) | ||
316 | { | ||
317 | struct link_master *master = snd_kcontrol_chip(kcontrol); | ||
318 | struct link_slave *slave; | ||
319 | |||
320 | list_for_each_entry(slave, &master->slaves, list) | ||
321 | slave->master = NULL; | ||
322 | kfree(master); | ||
323 | } | ||
324 | |||
325 | |||
326 | /* | ||
327 | * Create a virtual master control with the given name | ||
328 | */ | ||
329 | struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | ||
330 | const unsigned int *tlv) | ||
331 | { | ||
332 | struct link_master *master; | ||
333 | struct snd_kcontrol *kctl; | ||
334 | struct snd_kcontrol_new knew; | ||
335 | |||
336 | memset(&knew, 0, sizeof(knew)); | ||
337 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
338 | knew.name = name; | ||
339 | knew.info = master_info; | ||
340 | |||
341 | master = kzalloc(sizeof(*master), GFP_KERNEL); | ||
342 | if (!master) | ||
343 | return NULL; | ||
344 | INIT_LIST_HEAD(&master->slaves); | ||
345 | |||
346 | kctl = snd_ctl_new1(&knew, master); | ||
347 | if (!kctl) { | ||
348 | kfree(master); | ||
349 | return NULL; | ||
350 | } | ||
351 | /* override some callbacks */ | ||
352 | kctl->info = master_info; | ||
353 | kctl->get = master_get; | ||
354 | kctl->put = master_put; | ||
355 | kctl->private_free = master_free; | ||
356 | |||
357 | /* additional (constant) TLV read */ | ||
358 | if (tlv) { | ||
359 | /* FIXME: this assumes that the max volume is 0 dB */ | ||
360 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
361 | kctl->tlv.p = tlv; | ||
362 | } | ||
363 | return kctl; | ||
364 | } | ||
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 65ce66adba5a..f99fe089495d 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o |
7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o |
8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o |
9 | 9 | ||
10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o |
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c index a1aba0d7d0e4..dab31b2756a6 100644 --- a/sound/pci/ice1712/ak4xxx.c +++ b/sound/pci/ice1712/ak4xxx.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index 6e13d758bb5d..37564300b50d 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index ec0699c89952..868ae291b960 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
@@ -47,7 +47,6 @@ | |||
47 | * | 47 | * |
48 | */ | 48 | */ |
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | 50 | #include <asm/io.h> |
52 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
@@ -62,6 +61,15 @@ | |||
62 | #include "aureon.h" | 61 | #include "aureon.h" |
63 | #include <sound/tlv.h> | 62 | #include <sound/tlv.h> |
64 | 63 | ||
64 | /* AC97 register cache for Aureon */ | ||
65 | struct aureon_spec { | ||
66 | unsigned short stac9744[64]; | ||
67 | unsigned int cs8415_mux; | ||
68 | unsigned short master[2]; | ||
69 | unsigned short vol[8]; | ||
70 | unsigned char pca9554_out; | ||
71 | }; | ||
72 | |||
65 | /* WM8770 registers */ | 73 | /* WM8770 registers */ |
66 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 74 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
67 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ | 75 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ |
@@ -205,7 +213,8 @@ static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol, | |||
205 | struct snd_ctl_elem_value *ucontrol) | 213 | struct snd_ctl_elem_value *ucontrol) |
206 | { | 214 | { |
207 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 215 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
208 | ucontrol->value.integer.value[0] = ice->spec.aureon.pca9554_out; | 216 | struct aureon_spec *spec = ice->spec; |
217 | ucontrol->value.enumerated.item[0] = spec->pca9554_out; | ||
209 | return 0; | 218 | return 0; |
210 | } | 219 | } |
211 | 220 | ||
@@ -213,16 +222,18 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol, | |||
213 | struct snd_ctl_elem_value *ucontrol) | 222 | struct snd_ctl_elem_value *ucontrol) |
214 | { | 223 | { |
215 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 224 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
225 | struct aureon_spec *spec = ice->spec; | ||
216 | unsigned char oval, nval; | 226 | unsigned char oval, nval; |
217 | int change; | 227 | int change; |
218 | 228 | ||
229 | nval = ucontrol->value.enumerated.item[0]; | ||
230 | if (nval >= 3) | ||
231 | return -EINVAL; | ||
219 | snd_ice1712_save_gpio_status(ice); | 232 | snd_ice1712_save_gpio_status(ice); |
220 | 233 | oval = spec->pca9554_out; | |
221 | oval = ice->spec.aureon.pca9554_out; | ||
222 | nval = ucontrol->value.integer.value[0]; | ||
223 | if ((change = (oval != nval))) { | 234 | if ((change = (oval != nval))) { |
224 | aureon_pca9554_write(ice, PCA9554_OUT, nval); | 235 | aureon_pca9554_write(ice, PCA9554_OUT, nval); |
225 | ice->spec.aureon.pca9554_out = nval; | 236 | spec->pca9554_out = nval; |
226 | } | 237 | } |
227 | snd_ice1712_restore_gpio_status(ice); | 238 | snd_ice1712_restore_gpio_status(ice); |
228 | 239 | ||
@@ -233,6 +244,7 @@ static int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol, | |||
233 | static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, | 244 | static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, |
234 | unsigned short val) | 245 | unsigned short val) |
235 | { | 246 | { |
247 | struct aureon_spec *spec = ice->spec; | ||
236 | unsigned int tmp; | 248 | unsigned int tmp; |
237 | 249 | ||
238 | /* Send address to XILINX chip */ | 250 | /* Send address to XILINX chip */ |
@@ -280,12 +292,13 @@ static void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, | |||
280 | udelay(10); | 292 | udelay(10); |
281 | 293 | ||
282 | /* Store the data in out private buffer */ | 294 | /* Store the data in out private buffer */ |
283 | ice->spec.aureon.stac9744[(reg & 0x7F) >> 1] = val; | 295 | spec->stac9744[(reg & 0x7F) >> 1] = val; |
284 | } | 296 | } |
285 | 297 | ||
286 | static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg) | 298 | static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg) |
287 | { | 299 | { |
288 | return ice->spec.aureon.stac9744[(reg & 0x7F) >> 1]; | 300 | struct aureon_spec *spec = ice->spec; |
301 | return spec->stac9744[(reg & 0x7F) >> 1]; | ||
289 | } | 302 | } |
290 | 303 | ||
291 | /* | 304 | /* |
@@ -293,6 +306,7 @@ static unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short r | |||
293 | */ | 306 | */ |
294 | static int aureon_ac97_init (struct snd_ice1712 *ice) | 307 | static int aureon_ac97_init (struct snd_ice1712 *ice) |
295 | { | 308 | { |
309 | struct aureon_spec *spec = ice->spec; | ||
296 | int i; | 310 | int i; |
297 | static const unsigned short ac97_defaults[] = { | 311 | static const unsigned short ac97_defaults[] = { |
298 | 0x00, 0x9640, | 312 | 0x00, 0x9640, |
@@ -330,9 +344,9 @@ static int aureon_ac97_init (struct snd_ice1712 *ice) | |||
330 | snd_ice1712_gpio_write(ice, tmp); | 344 | snd_ice1712_gpio_write(ice, tmp); |
331 | udelay(3); | 345 | udelay(3); |
332 | 346 | ||
333 | memset(&ice->spec.aureon.stac9744, 0, sizeof(ice->spec.aureon.stac9744)); | 347 | memset(&spec->stac9744, 0, sizeof(spec->stac9744)); |
334 | for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2) | 348 | for (i=0; ac97_defaults[i] != (unsigned short)-1; i+=2) |
335 | ice->spec.aureon.stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1]; | 349 | spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1]; |
336 | 350 | ||
337 | aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770 | 351 | aureon_ac97_write(ice, AC97_MASTER, 0x0000); // Unmute AC'97 master volume permanently - muting is done by WM8770 |
338 | 352 | ||
@@ -744,27 +758,33 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
744 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 758 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
745 | { | 759 | { |
746 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 760 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
761 | struct aureon_spec *spec = ice->spec; | ||
747 | int i; | 762 | int i; |
748 | for (i=0; i<2; i++) | 763 | for (i=0; i<2; i++) |
749 | ucontrol->value.integer.value[i] = ice->spec.aureon.master[i] & ~WM_VOL_MUTE; | 764 | ucontrol->value.integer.value[i] = |
765 | spec->master[i] & ~WM_VOL_MUTE; | ||
750 | return 0; | 766 | return 0; |
751 | } | 767 | } |
752 | 768 | ||
753 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 769 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
754 | { | 770 | { |
755 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 771 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
772 | struct aureon_spec *spec = ice->spec; | ||
756 | int ch, change = 0; | 773 | int ch, change = 0; |
757 | 774 | ||
758 | snd_ice1712_save_gpio_status(ice); | 775 | snd_ice1712_save_gpio_status(ice); |
759 | for (ch = 0; ch < 2; ch++) { | 776 | for (ch = 0; ch < 2; ch++) { |
760 | if (ucontrol->value.integer.value[ch] != ice->spec.aureon.master[ch]) { | 777 | unsigned int vol = ucontrol->value.integer.value[ch]; |
778 | if (vol > WM_VOL_MAX) | ||
779 | continue; | ||
780 | vol |= spec->master[ch] & WM_VOL_MUTE; | ||
781 | if (vol != spec->master[ch]) { | ||
761 | int dac; | 782 | int dac; |
762 | ice->spec.aureon.master[ch] &= WM_VOL_MUTE; | 783 | spec->master[ch] = vol; |
763 | ice->spec.aureon.master[ch] |= ucontrol->value.integer.value[ch]; | ||
764 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 784 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
765 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, | 785 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, |
766 | ice->spec.aureon.vol[dac + ch], | 786 | spec->vol[dac + ch], |
767 | ice->spec.aureon.master[ch]); | 787 | spec->master[ch]); |
768 | change = 1; | 788 | change = 1; |
769 | } | 789 | } |
770 | } | 790 | } |
@@ -788,18 +808,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * | |||
788 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 808 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
789 | { | 809 | { |
790 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 810 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
811 | struct aureon_spec *spec = ice->spec; | ||
791 | int i, ofs, voices; | 812 | int i, ofs, voices; |
792 | 813 | ||
793 | voices = kcontrol->private_value >> 8; | 814 | voices = kcontrol->private_value >> 8; |
794 | ofs = kcontrol->private_value & 0xff; | 815 | ofs = kcontrol->private_value & 0xff; |
795 | for (i = 0; i < voices; i++) | 816 | for (i = 0; i < voices; i++) |
796 | ucontrol->value.integer.value[i] = ice->spec.aureon.vol[ofs+i] & ~WM_VOL_MUTE; | 817 | ucontrol->value.integer.value[i] = |
818 | spec->vol[ofs+i] & ~WM_VOL_MUTE; | ||
797 | return 0; | 819 | return 0; |
798 | } | 820 | } |
799 | 821 | ||
800 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 822 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
801 | { | 823 | { |
802 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 824 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
825 | struct aureon_spec *spec = ice->spec; | ||
803 | int i, idx, ofs, voices; | 826 | int i, idx, ofs, voices; |
804 | int change = 0; | 827 | int change = 0; |
805 | 828 | ||
@@ -807,12 +830,15 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * | |||
807 | ofs = kcontrol->private_value & 0xff; | 830 | ofs = kcontrol->private_value & 0xff; |
808 | snd_ice1712_save_gpio_status(ice); | 831 | snd_ice1712_save_gpio_status(ice); |
809 | for (i = 0; i < voices; i++) { | 832 | for (i = 0; i < voices; i++) { |
810 | idx = WM_DAC_ATTEN + ofs + i; | 833 | unsigned int vol = ucontrol->value.integer.value[i]; |
811 | if (ucontrol->value.integer.value[i] != ice->spec.aureon.vol[ofs+i]) { | 834 | if (vol > 0x7f) |
812 | ice->spec.aureon.vol[ofs+i] &= WM_VOL_MUTE; | 835 | continue; |
813 | ice->spec.aureon.vol[ofs+i] |= ucontrol->value.integer.value[i]; | 836 | vol |= spec->vol[ofs+i]; |
814 | wm_set_vol(ice, idx, ice->spec.aureon.vol[ofs+i], | 837 | if (vol != spec->vol[ofs+i]) { |
815 | ice->spec.aureon.master[i]); | 838 | spec->vol[ofs+i] = vol; |
839 | idx = WM_DAC_ATTEN + ofs + i; | ||
840 | wm_set_vol(ice, idx, spec->vol[ofs + i], | ||
841 | spec->master[i]); | ||
816 | change = 1; | 842 | change = 1; |
817 | } | 843 | } |
818 | } | 844 | } |
@@ -834,19 +860,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info | |||
834 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 860 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
835 | { | 861 | { |
836 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 862 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
863 | struct aureon_spec *spec = ice->spec; | ||
837 | int voices, ofs, i; | 864 | int voices, ofs, i; |
838 | 865 | ||
839 | voices = kcontrol->private_value >> 8; | 866 | voices = kcontrol->private_value >> 8; |
840 | ofs = kcontrol->private_value & 0xFF; | 867 | ofs = kcontrol->private_value & 0xFF; |
841 | 868 | ||
842 | for (i = 0; i < voices; i++) | 869 | for (i = 0; i < voices; i++) |
843 | ucontrol->value.integer.value[i] = (ice->spec.aureon.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | 870 | ucontrol->value.integer.value[i] = |
871 | (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | ||
844 | return 0; | 872 | return 0; |
845 | } | 873 | } |
846 | 874 | ||
847 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 875 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
848 | { | 876 | { |
849 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 877 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
878 | struct aureon_spec *spec = ice->spec; | ||
850 | int change = 0, voices, ofs, i; | 879 | int change = 0, voices, ofs, i; |
851 | 880 | ||
852 | voices = kcontrol->private_value >> 8; | 881 | voices = kcontrol->private_value >> 8; |
@@ -854,13 +883,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
854 | 883 | ||
855 | snd_ice1712_save_gpio_status(ice); | 884 | snd_ice1712_save_gpio_status(ice); |
856 | for (i = 0; i < voices; i++) { | 885 | for (i = 0; i < voices; i++) { |
857 | int val = (ice->spec.aureon.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | 886 | int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; |
858 | if (ucontrol->value.integer.value[i] != val) { | 887 | if (ucontrol->value.integer.value[i] != val) { |
859 | ice->spec.aureon.vol[ofs + i] &= ~WM_VOL_MUTE; | 888 | spec->vol[ofs + i] &= ~WM_VOL_MUTE; |
860 | ice->spec.aureon.vol[ofs + i] |= | 889 | spec->vol[ofs + i] |= |
861 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 890 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
862 | wm_set_vol(ice, ofs + i, ice->spec.aureon.vol[ofs + i], | 891 | wm_set_vol(ice, ofs + i, spec->vol[ofs + i], |
863 | ice->spec.aureon.master[i]); | 892 | spec->master[i]); |
864 | change = 1; | 893 | change = 1; |
865 | } | 894 | } |
866 | } | 895 | } |
@@ -877,29 +906,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
877 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 906 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
878 | { | 907 | { |
879 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 908 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
909 | struct aureon_spec *spec = ice->spec; | ||
880 | 910 | ||
881 | ucontrol->value.integer.value[0] = (ice->spec.aureon.master[0] & WM_VOL_MUTE) ? 0 : 1; | 911 | ucontrol->value.integer.value[0] = |
882 | ucontrol->value.integer.value[1] = (ice->spec.aureon.master[1] & WM_VOL_MUTE) ? 0 : 1; | 912 | (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; |
913 | ucontrol->value.integer.value[1] = | ||
914 | (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; | ||
883 | return 0; | 915 | return 0; |
884 | } | 916 | } |
885 | 917 | ||
886 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 918 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
887 | { | 919 | { |
888 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 920 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
921 | struct aureon_spec *spec = ice->spec; | ||
889 | int change = 0, i; | 922 | int change = 0, i; |
890 | 923 | ||
891 | snd_ice1712_save_gpio_status(ice); | 924 | snd_ice1712_save_gpio_status(ice); |
892 | for (i = 0; i < 2; i++) { | 925 | for (i = 0; i < 2; i++) { |
893 | int val = (ice->spec.aureon.master[i] & WM_VOL_MUTE) ? 0 : 1; | 926 | int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; |
894 | if (ucontrol->value.integer.value[i] != val) { | 927 | if (ucontrol->value.integer.value[i] != val) { |
895 | int dac; | 928 | int dac; |
896 | ice->spec.aureon.master[i] &= ~WM_VOL_MUTE; | 929 | spec->master[i] &= ~WM_VOL_MUTE; |
897 | ice->spec.aureon.master[i] |= | 930 | spec->master[i] |= |
898 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 931 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
899 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 932 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
900 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, | 933 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, |
901 | ice->spec.aureon.vol[dac + i], | 934 | spec->vol[dac + i], |
902 | ice->spec.aureon.master[i]); | 935 | spec->master[i]); |
903 | change = 1; | 936 | change = 1; |
904 | } | 937 | } |
905 | } | 938 | } |
@@ -940,8 +973,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
940 | unsigned short ovol, nvol; | 973 | unsigned short ovol, nvol; |
941 | int change = 0; | 974 | int change = 0; |
942 | 975 | ||
943 | snd_ice1712_save_gpio_status(ice); | ||
944 | nvol = ucontrol->value.integer.value[0]; | 976 | nvol = ucontrol->value.integer.value[0]; |
977 | if (nvol > PCM_RES) | ||
978 | return -EINVAL; | ||
979 | snd_ice1712_save_gpio_status(ice); | ||
945 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; | 980 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; |
946 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | 981 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; |
947 | if (ovol != nvol) { | 982 | if (ovol != nvol) { |
@@ -1031,7 +1066,7 @@ static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
1031 | snd_ice1712_save_gpio_status(ice); | 1066 | snd_ice1712_save_gpio_status(ice); |
1032 | for (i = 0; i < 2; i++) { | 1067 | for (i = 0; i < 2; i++) { |
1033 | idx = WM_ADC_GAIN + i; | 1068 | idx = WM_ADC_GAIN + i; |
1034 | nvol = ucontrol->value.integer.value[i]; | 1069 | nvol = ucontrol->value.integer.value[i] & 0x1f; |
1035 | ovol = wm_get(ice, idx); | 1070 | ovol = wm_get(ice, idx); |
1036 | if ((ovol & 0x1f) != nvol) { | 1071 | if ((ovol & 0x1f) != nvol) { |
1037 | wm_put(ice, idx, nvol | (ovol & ~0x1f)); | 1072 | wm_put(ice, idx, nvol | (ovol & ~0x1f)); |
@@ -1143,10 +1178,11 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1143 | static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1178 | static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1144 | { | 1179 | { |
1145 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1180 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1181 | struct aureon_spec *spec = ice->spec; | ||
1146 | 1182 | ||
1147 | //snd_ice1712_save_gpio_status(ice); | 1183 | //snd_ice1712_save_gpio_status(ice); |
1148 | //val = aureon_cs8415_get(ice, CS8415_CTRL2); | 1184 | //val = aureon_cs8415_get(ice, CS8415_CTRL2); |
1149 | ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux; | 1185 | ucontrol->value.enumerated.item[0] = spec->cs8415_mux; |
1150 | //snd_ice1712_restore_gpio_status(ice); | 1186 | //snd_ice1712_restore_gpio_status(ice); |
1151 | return 0; | 1187 | return 0; |
1152 | } | 1188 | } |
@@ -1154,6 +1190,7 @@ static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1154 | static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 1190 | static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1155 | { | 1191 | { |
1156 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 1192 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
1193 | struct aureon_spec *spec = ice->spec; | ||
1157 | unsigned short oval, nval; | 1194 | unsigned short oval, nval; |
1158 | int change; | 1195 | int change; |
1159 | 1196 | ||
@@ -1165,7 +1202,7 @@ static int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1165 | if (change) | 1202 | if (change) |
1166 | aureon_cs8415_put(ice, CS8415_CTRL2, nval); | 1203 | aureon_cs8415_put(ice, CS8415_CTRL2, nval); |
1167 | snd_ice1712_restore_gpio_status(ice); | 1204 | snd_ice1712_restore_gpio_status(ice); |
1168 | ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0]; | 1205 | spec->cs8415_mux = ucontrol->value.enumerated.item[0]; |
1169 | return change; | 1206 | return change; |
1170 | } | 1207 | } |
1171 | 1208 | ||
@@ -2001,10 +2038,16 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2001 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ | 2038 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ |
2002 | (unsigned short)-1 | 2039 | (unsigned short)-1 |
2003 | }; | 2040 | }; |
2041 | struct aureon_spec *spec; | ||
2004 | unsigned int tmp; | 2042 | unsigned int tmp; |
2005 | const unsigned short *p; | 2043 | const unsigned short *p; |
2006 | int err, i; | 2044 | int err, i; |
2007 | 2045 | ||
2046 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2047 | if (!spec) | ||
2048 | return -ENOMEM; | ||
2049 | ice->spec = spec; | ||
2050 | |||
2008 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | 2051 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { |
2009 | ice->num_total_dacs = 6; | 2052 | ice->num_total_dacs = 6; |
2010 | ice->num_total_adcs = 2; | 2053 | ice->num_total_adcs = 2; |
@@ -2055,7 +2098,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2055 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { | 2098 | ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { |
2056 | for (p = cs_inits; *p != (unsigned short)-1; p++) | 2099 | for (p = cs_inits; *p != (unsigned short)-1; p++) |
2057 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); | 2100 | aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); |
2058 | ice->spec.aureon.cs8415_mux = 1; | 2101 | spec->cs8415_mux = 1; |
2059 | 2102 | ||
2060 | aureon_set_headphone_amp(ice, 1); | 2103 | aureon_set_headphone_amp(ice, 1); |
2061 | } | 2104 | } |
@@ -2066,11 +2109,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
2066 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); | 2109 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); |
2067 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ | 2110 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ |
2068 | 2111 | ||
2069 | ice->spec.aureon.master[0] = WM_VOL_MUTE; | 2112 | spec->master[0] = WM_VOL_MUTE; |
2070 | ice->spec.aureon.master[1] = WM_VOL_MUTE; | 2113 | spec->master[1] = WM_VOL_MUTE; |
2071 | for (i = 0; i < ice->num_total_dacs; i++) { | 2114 | for (i = 0; i < ice->num_total_dacs; i++) { |
2072 | ice->spec.aureon.vol[i] = WM_VOL_MUTE; | 2115 | spec->vol[i] = WM_VOL_MUTE; |
2073 | wm_set_vol(ice, i, ice->spec.aureon.vol[i], ice->spec.aureon.master[i % 2]); | 2116 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
2074 | } | 2117 | } |
2075 | 2118 | ||
2076 | return 0; | 2119 | return 0; |
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 371f78461db4..efd180b40e56 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -405,7 +404,7 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco | |||
405 | if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) | 404 | if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) |
406 | snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); | 405 | snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); |
407 | snd_i2c_readbytes(ice->cs8427, ®, 1); | 406 | snd_i2c_readbytes(ice->cs8427, ®, 1); |
408 | ucontrol->value.integer.value[0] = (reg ? 1 : 0); | 407 | ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0; |
409 | return 0; | 408 | return 0; |
410 | } | 409 | } |
411 | 410 | ||
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 75e4e5e0f1e4..064760d2a027 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -45,6 +44,11 @@ enum { | |||
45 | }; | 44 | }; |
46 | 45 | ||
47 | 46 | ||
47 | /* additional i2c devices for EWS boards */ | ||
48 | struct ews_spec { | ||
49 | struct snd_i2c_device *i2cdevs[3]; | ||
50 | }; | ||
51 | |||
48 | /* | 52 | /* |
49 | * access via i2c mode (for EWX 24/96, EWS 88MT&D) | 53 | * access via i2c mode (for EWX 24/96, EWS 88MT&D) |
50 | */ | 54 | */ |
@@ -142,15 +146,17 @@ static struct snd_i2c_bit_ops snd_ice1712_ewx_cs8427_bit_ops = { | |||
142 | /* AK4524 chip select; address 0x48 bit 0-3 */ | 146 | /* AK4524 chip select; address 0x48 bit 0-3 */ |
143 | static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask) | 147 | static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mask) |
144 | { | 148 | { |
149 | struct ews_spec *spec = ice->spec; | ||
145 | unsigned char data, ndata; | 150 | unsigned char data, ndata; |
146 | 151 | ||
147 | snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL); | 152 | snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL); |
148 | snd_i2c_lock(ice->i2c); | 153 | snd_i2c_lock(ice->i2c); |
149 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) | 154 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) |
150 | goto __error; | 155 | goto __error; |
151 | ndata = (data & 0xf0) | chip_mask; | 156 | ndata = (data & 0xf0) | chip_mask; |
152 | if (ndata != data) | 157 | if (ndata != data) |
153 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1) | 158 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], &ndata, 1) |
159 | != 1) | ||
154 | goto __error; | 160 | goto __error; |
155 | snd_i2c_unlock(ice->i2c); | 161 | snd_i2c_unlock(ice->i2c); |
156 | return 0; | 162 | return 0; |
@@ -224,6 +230,7 @@ static void dmx6fire_ak4524_lock(struct snd_akm4xxx *ak, int chip) | |||
224 | 230 | ||
225 | static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits) | 231 | static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned char bits) |
226 | { | 232 | { |
233 | struct ews_spec *spec = ice->spec; | ||
227 | unsigned char bytes[2]; | 234 | unsigned char bytes[2]; |
228 | 235 | ||
229 | snd_i2c_lock(ice->i2c); | 236 | snd_i2c_lock(ice->i2c); |
@@ -231,15 +238,18 @@ static void snd_ice1712_ews_cs8404_spdif_write(struct snd_ice1712 *ice, unsigned | |||
231 | case ICE1712_SUBDEVICE_EWS88MT: | 238 | case ICE1712_SUBDEVICE_EWS88MT: |
232 | case ICE1712_SUBDEVICE_EWS88MT_NEW: | 239 | case ICE1712_SUBDEVICE_EWS88MT_NEW: |
233 | case ICE1712_SUBDEVICE_PHASE88: | 240 | case ICE1712_SUBDEVICE_PHASE88: |
234 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_CS8404], &bits, 1) != 1) | 241 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_CS8404], &bits, 1) |
242 | != 1) | ||
235 | goto _error; | 243 | goto _error; |
236 | break; | 244 | break; |
237 | case ICE1712_SUBDEVICE_EWS88D: | 245 | case ICE1712_SUBDEVICE_EWS88D: |
238 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2) | 246 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], bytes, 2) |
247 | != 2) | ||
239 | goto _error; | 248 | goto _error; |
240 | if (bits != bytes[1]) { | 249 | if (bits != bytes[1]) { |
241 | bytes[1] = bits; | 250 | bytes[1] = bits; |
242 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2) | 251 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], |
252 | bytes, 2) != 2) | ||
243 | goto _error; | 253 | goto _error; |
244 | } | 254 | } |
245 | break; | 255 | break; |
@@ -412,6 +422,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
412 | { | 422 | { |
413 | int err; | 423 | int err; |
414 | struct snd_akm4xxx *ak; | 424 | struct snd_akm4xxx *ak; |
425 | struct ews_spec *spec; | ||
415 | 426 | ||
416 | /* set the analog DACs */ | 427 | /* set the analog DACs */ |
417 | switch (ice->eeprom.subvendor) { | 428 | switch (ice->eeprom.subvendor) { |
@@ -436,6 +447,11 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
436 | break; | 447 | break; |
437 | } | 448 | } |
438 | 449 | ||
450 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
451 | if (!spec) | ||
452 | return -ENOMEM; | ||
453 | ice->spec = spec; | ||
454 | |||
439 | /* create i2c */ | 455 | /* create i2c */ |
440 | if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { | 456 | if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { |
441 | snd_printk(KERN_ERR "unable to create I2C bus\n"); | 457 | snd_printk(KERN_ERR "unable to create I2C bus\n"); |
@@ -447,7 +463,10 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
447 | /* create i2c devices */ | 463 | /* create i2c devices */ |
448 | switch (ice->eeprom.subvendor) { | 464 | switch (ice->eeprom.subvendor) { |
449 | case ICE1712_SUBDEVICE_DMX6FIRE: | 465 | case ICE1712_SUBDEVICE_DMX6FIRE: |
450 | if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->spec.i2cdevs[EWS_I2C_6FIRE])) < 0) { | 466 | err = snd_i2c_device_create(ice->i2c, "PCF9554", |
467 | ICE1712_6FIRE_PCF9554_ADDR, | ||
468 | &spec->i2cdevs[EWS_I2C_6FIRE]); | ||
469 | if (err < 0) { | ||
451 | snd_printk(KERN_ERR "PCF9554 initialization failed\n"); | 470 | snd_printk(KERN_ERR "PCF9554 initialization failed\n"); |
452 | return err; | 471 | return err; |
453 | } | 472 | } |
@@ -456,18 +475,30 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
456 | case ICE1712_SUBDEVICE_EWS88MT: | 475 | case ICE1712_SUBDEVICE_EWS88MT: |
457 | case ICE1712_SUBDEVICE_EWS88MT_NEW: | 476 | case ICE1712_SUBDEVICE_EWS88MT_NEW: |
458 | case ICE1712_SUBDEVICE_PHASE88: | 477 | case ICE1712_SUBDEVICE_PHASE88: |
459 | if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->spec.i2cdevs[EWS_I2C_CS8404])) < 0) | 478 | err = snd_i2c_device_create(ice->i2c, "CS8404", |
479 | ICE1712_EWS88MT_CS8404_ADDR, | ||
480 | &spec->i2cdevs[EWS_I2C_CS8404]); | ||
481 | if (err < 0) | ||
460 | return err; | 482 | return err; |
461 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF1])) < 0) | 483 | err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", |
484 | ICE1712_EWS88MT_INPUT_ADDR, | ||
485 | &spec->i2cdevs[EWS_I2C_PCF1]); | ||
486 | if (err < 0) | ||
462 | return err; | 487 | return err; |
463 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", ICE1712_EWS88MT_OUTPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF2])) < 0) | 488 | err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", |
489 | ICE1712_EWS88MT_OUTPUT_ADDR, | ||
490 | &spec->i2cdevs[EWS_I2C_PCF2]); | ||
491 | if (err < 0) | ||
464 | return err; | 492 | return err; |
465 | /* Check if the front module is connected */ | 493 | /* Check if the front module is connected */ |
466 | if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0) | 494 | if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0) |
467 | return err; | 495 | return err; |
468 | break; | 496 | break; |
469 | case ICE1712_SUBDEVICE_EWS88D: | 497 | case ICE1712_SUBDEVICE_EWS88D: |
470 | if ((err = snd_i2c_device_create(ice->i2c, "PCF8575", ICE1712_EWS88D_PCF_ADDR, &ice->spec.i2cdevs[EWS_I2C_88D])) < 0) | 498 | err = snd_i2c_device_create(ice->i2c, "PCF8575", |
499 | ICE1712_EWS88D_PCF_ADDR, | ||
500 | &spec->i2cdevs[EWS_I2C_88D]); | ||
501 | if (err < 0) | ||
471 | return err; | 502 | return err; |
472 | break; | 503 | break; |
473 | } | 504 | } |
@@ -507,7 +538,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) | |||
507 | } | 538 | } |
508 | 539 | ||
509 | /* analog section */ | 540 | /* analog section */ |
510 | ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | 541 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); |
511 | if (! ak) | 542 | if (! ak) |
512 | return -ENOMEM; | 543 | return -ENOMEM; |
513 | ice->akm_codecs = 1; | 544 | ice->akm_codecs = 1; |
@@ -605,10 +636,11 @@ static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { | |||
605 | static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 636 | static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
606 | { | 637 | { |
607 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 638 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
639 | struct ews_spec *spec = ice->spec; | ||
608 | unsigned char data; | 640 | unsigned char data; |
609 | 641 | ||
610 | snd_i2c_lock(ice->i2c); | 642 | snd_i2c_lock(ice->i2c); |
611 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { | 643 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { |
612 | snd_i2c_unlock(ice->i2c); | 644 | snd_i2c_unlock(ice->i2c); |
613 | return -EIO; | 645 | return -EIO; |
614 | } | 646 | } |
@@ -621,15 +653,17 @@ static int snd_ice1712_ews88mt_output_sense_get(struct snd_kcontrol *kcontrol, s | |||
621 | static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 653 | static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
622 | { | 654 | { |
623 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 655 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
656 | struct ews_spec *spec = ice->spec; | ||
624 | unsigned char data, ndata; | 657 | unsigned char data, ndata; |
625 | 658 | ||
626 | snd_i2c_lock(ice->i2c); | 659 | snd_i2c_lock(ice->i2c); |
627 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { | 660 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF2], &data, 1) != 1) { |
628 | snd_i2c_unlock(ice->i2c); | 661 | snd_i2c_unlock(ice->i2c); |
629 | return -EIO; | 662 | return -EIO; |
630 | } | 663 | } |
631 | ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0); | 664 | ndata = (data & ~ICE1712_EWS88MT_OUTPUT_SENSE) | (ucontrol->value.enumerated.item[0] ? ICE1712_EWS88MT_OUTPUT_SENSE : 0); |
632 | if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1) { | 665 | if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF2], |
666 | &ndata, 1) != 1) { | ||
633 | snd_i2c_unlock(ice->i2c); | 667 | snd_i2c_unlock(ice->i2c); |
634 | return -EIO; | 668 | return -EIO; |
635 | } | 669 | } |
@@ -641,12 +675,13 @@ static int snd_ice1712_ews88mt_output_sense_put(struct snd_kcontrol *kcontrol, s | |||
641 | static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 675 | static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
642 | { | 676 | { |
643 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 677 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
678 | struct ews_spec *spec = ice->spec; | ||
644 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 679 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
645 | unsigned char data; | 680 | unsigned char data; |
646 | 681 | ||
647 | snd_assert(channel >= 0 && channel <= 7, return 0); | 682 | snd_assert(channel >= 0 && channel <= 7, return 0); |
648 | snd_i2c_lock(ice->i2c); | 683 | snd_i2c_lock(ice->i2c); |
649 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { | 684 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { |
650 | snd_i2c_unlock(ice->i2c); | 685 | snd_i2c_unlock(ice->i2c); |
651 | return -EIO; | 686 | return -EIO; |
652 | } | 687 | } |
@@ -660,17 +695,19 @@ static int snd_ice1712_ews88mt_input_sense_get(struct snd_kcontrol *kcontrol, st | |||
660 | static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 695 | static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
661 | { | 696 | { |
662 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 697 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
698 | struct ews_spec *spec = ice->spec; | ||
663 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 699 | int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
664 | unsigned char data, ndata; | 700 | unsigned char data, ndata; |
665 | 701 | ||
666 | snd_assert(channel >= 0 && channel <= 7, return 0); | 702 | snd_assert(channel >= 0 && channel <= 7, return 0); |
667 | snd_i2c_lock(ice->i2c); | 703 | snd_i2c_lock(ice->i2c); |
668 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { | 704 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_PCF1], &data, 1) != 1) { |
669 | snd_i2c_unlock(ice->i2c); | 705 | snd_i2c_unlock(ice->i2c); |
670 | return -EIO; | 706 | return -EIO; |
671 | } | 707 | } |
672 | ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel)); | 708 | ndata = (data & ~(1 << channel)) | (ucontrol->value.enumerated.item[0] ? 0 : (1 << channel)); |
673 | if (ndata != data && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF1], &ndata, 1) != 1) { | 709 | if (ndata != data && snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_PCF1], |
710 | &ndata, 1) != 1) { | ||
674 | snd_i2c_unlock(ice->i2c); | 711 | snd_i2c_unlock(ice->i2c); |
675 | return -EIO; | 712 | return -EIO; |
676 | } | 713 | } |
@@ -705,12 +742,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = | |||
705 | static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 742 | static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
706 | { | 743 | { |
707 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 744 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
745 | struct ews_spec *spec = ice->spec; | ||
708 | int shift = kcontrol->private_value & 0xff; | 746 | int shift = kcontrol->private_value & 0xff; |
709 | int invert = (kcontrol->private_value >> 8) & 1; | 747 | int invert = (kcontrol->private_value >> 8) & 1; |
710 | unsigned char data[2]; | 748 | unsigned char data[2]; |
711 | 749 | ||
712 | snd_i2c_lock(ice->i2c); | 750 | snd_i2c_lock(ice->i2c); |
713 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 751 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { |
714 | snd_i2c_unlock(ice->i2c); | 752 | snd_i2c_unlock(ice->i2c); |
715 | return -EIO; | 753 | return -EIO; |
716 | } | 754 | } |
@@ -725,13 +763,14 @@ static int snd_ice1712_ews88d_control_get(struct snd_kcontrol *kcontrol, struct | |||
725 | static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 763 | static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
726 | { | 764 | { |
727 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 765 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
766 | struct ews_spec *spec = ice->spec; | ||
728 | int shift = kcontrol->private_value & 0xff; | 767 | int shift = kcontrol->private_value & 0xff; |
729 | int invert = (kcontrol->private_value >> 8) & 1; | 768 | int invert = (kcontrol->private_value >> 8) & 1; |
730 | unsigned char data[2], ndata[2]; | 769 | unsigned char data[2], ndata[2]; |
731 | int change; | 770 | int change; |
732 | 771 | ||
733 | snd_i2c_lock(ice->i2c); | 772 | snd_i2c_lock(ice->i2c); |
734 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 773 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { |
735 | snd_i2c_unlock(ice->i2c); | 774 | snd_i2c_unlock(ice->i2c); |
736 | return -EIO; | 775 | return -EIO; |
737 | } | 776 | } |
@@ -744,7 +783,8 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct | |||
744 | ndata[shift >> 3] |= (1 << (shift & 7)); | 783 | ndata[shift >> 3] |= (1 << (shift & 7)); |
745 | } | 784 | } |
746 | change = (data[shift >> 3] != ndata[shift >> 3]); | 785 | change = (data[shift >> 3] != ndata[shift >> 3]); |
747 | if (change && snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], data, 2) != 2) { | 786 | if (change && |
787 | snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_88D], data, 2) != 2) { | ||
748 | snd_i2c_unlock(ice->i2c); | 788 | snd_i2c_unlock(ice->i2c); |
749 | return -EIO; | 789 | return -EIO; |
750 | } | 790 | } |
@@ -778,11 +818,13 @@ static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { | |||
778 | static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg) | 818 | static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg) |
779 | { | 819 | { |
780 | unsigned char byte; | 820 | unsigned char byte; |
821 | struct ews_spec *spec = ice->spec; | ||
822 | |||
781 | snd_i2c_lock(ice->i2c); | 823 | snd_i2c_lock(ice->i2c); |
782 | byte = reg; | 824 | byte = reg; |
783 | snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1); | 825 | snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1); |
784 | byte = 0; | 826 | byte = 0; |
785 | if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { | 827 | if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { |
786 | snd_i2c_unlock(ice->i2c); | 828 | snd_i2c_unlock(ice->i2c); |
787 | printk(KERN_ERR "cannot read pca\n"); | 829 | printk(KERN_ERR "cannot read pca\n"); |
788 | return -EIO; | 830 | return -EIO; |
@@ -794,10 +836,12 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg | |||
794 | static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data) | 836 | static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data) |
795 | { | 837 | { |
796 | unsigned char bytes[2]; | 838 | unsigned char bytes[2]; |
839 | struct ews_spec *spec = ice->spec; | ||
840 | |||
797 | snd_i2c_lock(ice->i2c); | 841 | snd_i2c_lock(ice->i2c); |
798 | bytes[0] = reg; | 842 | bytes[0] = reg; |
799 | bytes[1] = data; | 843 | bytes[1] = data; |
800 | if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) { | 844 | if (snd_i2c_sendbytes(spec->i2cdevs[EWS_I2C_6FIRE], bytes, 2) != 2) { |
801 | snd_i2c_unlock(ice->i2c); | 845 | snd_i2c_unlock(ice->i2c); |
802 | return -EIO; | 846 | return -EIO; |
803 | } | 847 | } |
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index abcfd1da6587..cf5c7c0898fd 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -34,6 +33,12 @@ | |||
34 | #include "ice1712.h" | 33 | #include "ice1712.h" |
35 | #include "hoontech.h" | 34 | #include "hoontech.h" |
36 | 35 | ||
36 | /* Hoontech-specific setting */ | ||
37 | struct hoontech_spec { | ||
38 | unsigned char boxbits[4]; | ||
39 | unsigned int config; | ||
40 | unsigned short boxconfig[4]; | ||
41 | }; | ||
37 | 42 | ||
38 | static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) | 43 | static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) |
39 | { | 44 | { |
@@ -50,169 +55,182 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un | |||
50 | 55 | ||
51 | static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) | 56 | static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) |
52 | { | 57 | { |
58 | struct hoontech_spec *spec = ice->spec; | ||
53 | mutex_lock(&ice->gpio_mutex); | 59 | mutex_lock(&ice->gpio_mutex); |
54 | ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate); | 60 | ICE1712_STDSP24_0_DAREAR(spec->boxbits, activate); |
55 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 61 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
56 | mutex_unlock(&ice->gpio_mutex); | 62 | mutex_unlock(&ice->gpio_mutex); |
57 | } | 63 | } |
58 | 64 | ||
59 | static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) | 65 | static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) |
60 | { | 66 | { |
67 | struct hoontech_spec *spec = ice->spec; | ||
61 | mutex_lock(&ice->gpio_mutex); | 68 | mutex_lock(&ice->gpio_mutex); |
62 | ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate); | 69 | ICE1712_STDSP24_3_MUTE(spec->boxbits, activate); |
63 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 70 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
64 | mutex_unlock(&ice->gpio_mutex); | 71 | mutex_unlock(&ice->gpio_mutex); |
65 | } | 72 | } |
66 | 73 | ||
67 | static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) | 74 | static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) |
68 | { | 75 | { |
76 | struct hoontech_spec *spec = ice->spec; | ||
69 | mutex_lock(&ice->gpio_mutex); | 77 | mutex_lock(&ice->gpio_mutex); |
70 | ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate); | 78 | ICE1712_STDSP24_3_INSEL(spec->boxbits, activate); |
71 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 79 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
72 | mutex_unlock(&ice->gpio_mutex); | 80 | mutex_unlock(&ice->gpio_mutex); |
73 | } | 81 | } |
74 | 82 | ||
75 | static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) | 83 | static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) |
76 | { | 84 | { |
85 | struct hoontech_spec *spec = ice->spec; | ||
86 | |||
77 | mutex_lock(&ice->gpio_mutex); | 87 | mutex_lock(&ice->gpio_mutex); |
78 | 88 | ||
79 | /* select box */ | 89 | /* select box */ |
80 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); | 90 | ICE1712_STDSP24_0_BOX(spec->boxbits, box); |
81 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 91 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
82 | 92 | ||
83 | /* prepare for write */ | 93 | /* prepare for write */ |
84 | if (chn == 3) | 94 | if (chn == 3) |
85 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); | 95 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); |
86 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, activate); | 96 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, activate); |
87 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 97 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
88 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 98 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
89 | 99 | ||
90 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 100 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
91 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 101 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
92 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 102 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
93 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 103 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
94 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 104 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
95 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 105 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
96 | udelay(100); | 106 | udelay(100); |
97 | if (chn == 3) { | 107 | if (chn == 3) { |
98 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 0); | 108 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 0); |
99 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 109 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
100 | } else { | 110 | } else { |
101 | switch (chn) { | 111 | switch (chn) { |
102 | case 0: ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 0); break; | 112 | case 0: ICE1712_STDSP24_1_CHN1(spec->boxbits, 0); break; |
103 | case 1: ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 0); break; | 113 | case 1: ICE1712_STDSP24_1_CHN2(spec->boxbits, 0); break; |
104 | case 2: ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 0); break; | 114 | case 2: ICE1712_STDSP24_1_CHN3(spec->boxbits, 0); break; |
105 | } | 115 | } |
106 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 116 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
107 | } | 117 | } |
108 | udelay(100); | 118 | udelay(100); |
109 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 119 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
110 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 120 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
111 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 121 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
112 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 122 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
113 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[1]); | 123 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[1]); |
114 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 124 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
115 | udelay(100); | 125 | udelay(100); |
116 | 126 | ||
117 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); | 127 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); |
118 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 128 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
119 | 129 | ||
120 | mutex_unlock(&ice->gpio_mutex); | 130 | mutex_unlock(&ice->gpio_mutex); |
121 | } | 131 | } |
122 | 132 | ||
123 | static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) | 133 | static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) |
124 | { | 134 | { |
135 | struct hoontech_spec *spec = ice->spec; | ||
136 | |||
125 | mutex_lock(&ice->gpio_mutex); | 137 | mutex_lock(&ice->gpio_mutex); |
126 | 138 | ||
127 | /* select box */ | 139 | /* select box */ |
128 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box); | 140 | ICE1712_STDSP24_0_BOX(spec->boxbits, box); |
129 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]); | 141 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[0]); |
130 | 142 | ||
131 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 143 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
132 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, master); | 144 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, master); |
133 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 145 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
134 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 146 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
135 | 147 | ||
136 | udelay(100); | 148 | udelay(100); |
137 | 149 | ||
138 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 0); | 150 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 0); |
139 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 151 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
140 | 152 | ||
141 | mdelay(10); | 153 | mdelay(10); |
142 | 154 | ||
143 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 155 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
144 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]); | 156 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[2]); |
145 | 157 | ||
146 | mutex_unlock(&ice->gpio_mutex); | 158 | mutex_unlock(&ice->gpio_mutex); |
147 | } | 159 | } |
148 | 160 | ||
149 | static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) | 161 | static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) |
150 | { | 162 | { |
163 | struct hoontech_spec *spec = ice->spec; | ||
151 | mutex_lock(&ice->gpio_mutex); | 164 | mutex_lock(&ice->gpio_mutex); |
152 | ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate); | 165 | ICE1712_STDSP24_3_MIDI2(spec->boxbits, activate); |
153 | snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]); | 166 | snd_ice1712_stdsp24_gpio_write(ice, spec->boxbits[3]); |
154 | mutex_unlock(&ice->gpio_mutex); | 167 | mutex_unlock(&ice->gpio_mutex); |
155 | } | 168 | } |
156 | 169 | ||
157 | static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) | 170 | static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) |
158 | { | 171 | { |
172 | struct hoontech_spec *spec; | ||
159 | int box, chn; | 173 | int box, chn; |
160 | 174 | ||
161 | ice->num_total_dacs = 8; | 175 | ice->num_total_dacs = 8; |
162 | ice->num_total_adcs = 8; | 176 | ice->num_total_adcs = 8; |
163 | 177 | ||
164 | ice->spec.hoontech.boxbits[0] = | 178 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
165 | ice->spec.hoontech.boxbits[1] = | 179 | if (!spec) |
166 | ice->spec.hoontech.boxbits[2] = | 180 | return -ENOMEM; |
167 | ice->spec.hoontech.boxbits[3] = 0; /* should be already */ | 181 | ice->spec = spec; |
168 | 182 | ||
169 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 0); | 183 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 0); |
170 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 0, 1); | 184 | ICE1712_STDSP24_CLOCK(spec->boxbits, 0, 1); |
171 | ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, 0); | 185 | ICE1712_STDSP24_0_BOX(spec->boxbits, 0); |
172 | ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, 0); | 186 | ICE1712_STDSP24_0_DAREAR(spec->boxbits, 0); |
173 | 187 | ||
174 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 1); | 188 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 1); |
175 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 1, 1); | 189 | ICE1712_STDSP24_CLOCK(spec->boxbits, 1, 1); |
176 | ICE1712_STDSP24_1_CHN1(ice->spec.hoontech.boxbits, 1); | 190 | ICE1712_STDSP24_1_CHN1(spec->boxbits, 1); |
177 | ICE1712_STDSP24_1_CHN2(ice->spec.hoontech.boxbits, 1); | 191 | ICE1712_STDSP24_1_CHN2(spec->boxbits, 1); |
178 | ICE1712_STDSP24_1_CHN3(ice->spec.hoontech.boxbits, 1); | 192 | ICE1712_STDSP24_1_CHN3(spec->boxbits, 1); |
179 | 193 | ||
180 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 2); | 194 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 2); |
181 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 2, 1); | 195 | ICE1712_STDSP24_CLOCK(spec->boxbits, 2, 1); |
182 | ICE1712_STDSP24_2_CHN4(ice->spec.hoontech.boxbits, 1); | 196 | ICE1712_STDSP24_2_CHN4(spec->boxbits, 1); |
183 | ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1); | 197 | ICE1712_STDSP24_2_MIDIIN(spec->boxbits, 1); |
184 | ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0); | 198 | ICE1712_STDSP24_2_MIDI1(spec->boxbits, 0); |
185 | 199 | ||
186 | ICE1712_STDSP24_SET_ADDR(ice->spec.hoontech.boxbits, 3); | 200 | ICE1712_STDSP24_SET_ADDR(spec->boxbits, 3); |
187 | ICE1712_STDSP24_CLOCK(ice->spec.hoontech.boxbits, 3, 1); | 201 | ICE1712_STDSP24_CLOCK(spec->boxbits, 3, 1); |
188 | ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, 0); | 202 | ICE1712_STDSP24_3_MIDI2(spec->boxbits, 0); |
189 | ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, 1); | 203 | ICE1712_STDSP24_3_MUTE(spec->boxbits, 1); |
190 | ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, 0); | 204 | ICE1712_STDSP24_3_INSEL(spec->boxbits, 0); |
191 | 205 | ||
192 | /* let's go - activate only functions in first box */ | 206 | /* let's go - activate only functions in first box */ |
193 | ice->spec.hoontech.config = 0; | 207 | spec->config = 0; |
194 | /* ICE1712_STDSP24_MUTE | | 208 | /* ICE1712_STDSP24_MUTE | |
195 | ICE1712_STDSP24_INSEL | | 209 | ICE1712_STDSP24_INSEL | |
196 | ICE1712_STDSP24_DAREAR; */ | 210 | ICE1712_STDSP24_DAREAR; */ |
197 | ice->spec.hoontech.boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | | 211 | spec->boxconfig[0] = ICE1712_STDSP24_BOX_CHN1 | |
198 | ICE1712_STDSP24_BOX_CHN2 | | 212 | ICE1712_STDSP24_BOX_CHN2 | |
199 | ICE1712_STDSP24_BOX_CHN3 | | 213 | ICE1712_STDSP24_BOX_CHN3 | |
200 | ICE1712_STDSP24_BOX_CHN4 | | 214 | ICE1712_STDSP24_BOX_CHN4 | |
201 | ICE1712_STDSP24_BOX_MIDI1 | | 215 | ICE1712_STDSP24_BOX_MIDI1 | |
202 | ICE1712_STDSP24_BOX_MIDI2; | 216 | ICE1712_STDSP24_BOX_MIDI2; |
203 | ice->spec.hoontech.boxconfig[1] = | 217 | spec->boxconfig[1] = |
204 | ice->spec.hoontech.boxconfig[2] = | 218 | spec->boxconfig[2] = |
205 | ice->spec.hoontech.boxconfig[3] = 0; | 219 | spec->boxconfig[3] = 0; |
206 | snd_ice1712_stdsp24_darear(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_DAREAR) ? 1 : 0); | 220 | snd_ice1712_stdsp24_darear(ice, |
207 | snd_ice1712_stdsp24_mute(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_MUTE) ? 1 : 0); | 221 | (spec->config & ICE1712_STDSP24_DAREAR) ? 1 : 0); |
208 | snd_ice1712_stdsp24_insel(ice, (ice->spec.hoontech.config & ICE1712_STDSP24_INSEL) ? 1 : 0); | 222 | snd_ice1712_stdsp24_mute(ice, |
209 | for (box = 0; box < 4; box++) { | 223 | (spec->config & ICE1712_STDSP24_MUTE) ? 1 : 0); |
224 | snd_ice1712_stdsp24_insel(ice, | ||
225 | (spec->config & ICE1712_STDSP24_INSEL) ? 1 : 0); | ||
226 | for (box = 0; box < 1; box++) { | ||
227 | if (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) | ||
228 | snd_ice1712_stdsp24_midi2(ice, 1); | ||
210 | for (chn = 0; chn < 4; chn++) | 229 | for (chn = 0; chn < 4; chn++) |
211 | snd_ice1712_stdsp24_box_channel(ice, box, chn, (ice->spec.hoontech.boxconfig[box] & (1 << chn)) ? 1 : 0); | 230 | snd_ice1712_stdsp24_box_channel(ice, box, chn, |
231 | (spec->boxconfig[box] & (1 << chn)) ? 1 : 0); | ||
212 | snd_ice1712_stdsp24_box_midi(ice, box, | 232 | snd_ice1712_stdsp24_box_midi(ice, box, |
213 | (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); | 233 | (spec->boxconfig[box] & ICE1712_STDSP24_BOX_MIDI1) ? 1 : 0); |
214 | if (ice->spec.hoontech.boxconfig[box] & ICE1712_STDSP24_BOX_MIDI2) | ||
215 | snd_ice1712_stdsp24_midi2(ice, 1); | ||
216 | } | 234 | } |
217 | 235 | ||
218 | return 0; | 236 | return 0; |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 052fc3cb3272..df292af67381 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
@@ -47,7 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | 50 | #include <asm/io.h> |
52 | #include <linux/delay.h> | 51 | #include <linux/delay.h> |
53 | #include <linux/interrupt.h> | 52 | #include <linux/interrupt.h> |
@@ -2491,6 +2490,7 @@ static int snd_ice1712_free(struct snd_ice1712 *ice) | |||
2491 | pci_release_regions(ice->pci); | 2490 | pci_release_regions(ice->pci); |
2492 | snd_ice1712_akm4xxx_free(ice); | 2491 | snd_ice1712_akm4xxx_free(ice); |
2493 | pci_disable_device(ice->pci); | 2492 | pci_disable_device(ice->pci); |
2493 | kfree(ice->spec); | ||
2494 | kfree(ice); | 2494 | kfree(ice); |
2495 | return 0; | 2495 | return 0; |
2496 | } | 2496 | } |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 58640afa5404..303cffe08bd8 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -366,42 +366,7 @@ struct snd_ice1712 { | |||
366 | struct mutex gpio_mutex; | 366 | struct mutex gpio_mutex; |
367 | 367 | ||
368 | /* other board-specific data */ | 368 | /* other board-specific data */ |
369 | union { | 369 | void *spec; |
370 | /* additional i2c devices for EWS boards */ | ||
371 | struct snd_i2c_device *i2cdevs[3]; | ||
372 | /* AC97 register cache for Aureon */ | ||
373 | struct aureon_spec { | ||
374 | unsigned short stac9744[64]; | ||
375 | unsigned int cs8415_mux; | ||
376 | unsigned short master[2]; | ||
377 | unsigned short vol[8]; | ||
378 | unsigned char pca9554_out; | ||
379 | } aureon; | ||
380 | /* AC97 register cache for Phase28 */ | ||
381 | struct phase28_spec { | ||
382 | unsigned short master[2]; | ||
383 | unsigned short vol[8]; | ||
384 | } phase28; | ||
385 | /* a non-standard I2C device for revo51 */ | ||
386 | struct revo51_spec { | ||
387 | struct snd_i2c_device *dev; | ||
388 | struct snd_pt2258 *pt2258; | ||
389 | } revo51; | ||
390 | /* Hoontech-specific setting */ | ||
391 | struct hoontech_spec { | ||
392 | unsigned char boxbits[4]; | ||
393 | unsigned int config; | ||
394 | unsigned short boxconfig[4]; | ||
395 | } hoontech; | ||
396 | struct { | ||
397 | struct ak4114 *ak4114; | ||
398 | unsigned int analog: 1; | ||
399 | } juli; | ||
400 | struct { | ||
401 | struct ak4114 *ak4114; | ||
402 | } prodigy192; | ||
403 | } spec; | ||
404 | |||
405 | }; | 370 | }; |
406 | 371 | ||
407 | 372 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 0b0bbb0d96b9..f533850ec6e7 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | 25 | #include <asm/io.h> |
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
@@ -48,9 +47,11 @@ | |||
48 | #include "vt1720_mobo.h" | 47 | #include "vt1720_mobo.h" |
49 | #include "pontis.h" | 48 | #include "pontis.h" |
50 | #include "prodigy192.h" | 49 | #include "prodigy192.h" |
50 | #include "prodigy_hifi.h" | ||
51 | #include "juli.h" | 51 | #include "juli.h" |
52 | #include "phase.h" | 52 | #include "phase.h" |
53 | #include "wtm.h" | 53 | #include "wtm.h" |
54 | #include "se.h" | ||
54 | 55 | ||
55 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 56 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
56 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); | 57 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); |
@@ -62,9 +63,11 @@ MODULE_SUPPORTED_DEVICE("{" | |||
62 | VT1720_MOBO_DEVICE_DESC | 63 | VT1720_MOBO_DEVICE_DESC |
63 | PONTIS_DEVICE_DESC | 64 | PONTIS_DEVICE_DESC |
64 | PRODIGY192_DEVICE_DESC | 65 | PRODIGY192_DEVICE_DESC |
66 | PRODIGY_HIFI_DEVICE_DESC | ||
65 | JULI_DEVICE_DESC | 67 | JULI_DEVICE_DESC |
66 | PHASE_DEVICE_DESC | 68 | PHASE_DEVICE_DESC |
67 | WTM_DEVICE_DESC | 69 | WTM_DEVICE_DESC |
70 | SE_DEVICE_DESC | ||
68 | "{VIA,VT1720}," | 71 | "{VIA,VT1720}," |
69 | "{VIA,VT1724}," | 72 | "{VIA,VT1724}," |
70 | "{ICEnsemble,Generic ICE1724}," | 73 | "{ICEnsemble,Generic ICE1724}," |
@@ -1929,10 +1932,12 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
1929 | snd_vt1724_aureon_cards, | 1932 | snd_vt1724_aureon_cards, |
1930 | snd_vt1720_mobo_cards, | 1933 | snd_vt1720_mobo_cards, |
1931 | snd_vt1720_pontis_cards, | 1934 | snd_vt1720_pontis_cards, |
1935 | snd_vt1724_prodigy_hifi_cards, | ||
1932 | snd_vt1724_prodigy192_cards, | 1936 | snd_vt1724_prodigy192_cards, |
1933 | snd_vt1724_juli_cards, | 1937 | snd_vt1724_juli_cards, |
1934 | snd_vt1724_phase_cards, | 1938 | snd_vt1724_phase_cards, |
1935 | snd_vt1724_wtm_cards, | 1939 | snd_vt1724_wtm_cards, |
1940 | snd_vt1724_se_cards, | ||
1936 | NULL, | 1941 | NULL, |
1937 | }; | 1942 | }; |
1938 | 1943 | ||
@@ -1955,6 +1960,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, | |||
1955 | unsigned char val; | 1960 | unsigned char val; |
1956 | 1961 | ||
1957 | mutex_lock(&ice->i2c_mutex); | 1962 | mutex_lock(&ice->i2c_mutex); |
1963 | wait_i2c_busy(ice); | ||
1958 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); | 1964 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); |
1959 | outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); | 1965 | outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); |
1960 | wait_i2c_busy(ice); | 1966 | wait_i2c_busy(ice); |
@@ -2170,6 +2176,7 @@ static int snd_vt1724_free(struct snd_ice1712 *ice) | |||
2170 | pci_release_regions(ice->pci); | 2176 | pci_release_regions(ice->pci); |
2171 | snd_ice1712_akm4xxx_free(ice); | 2177 | snd_ice1712_akm4xxx_free(ice); |
2172 | pci_disable_device(ice->pci); | 2178 | pci_disable_device(ice->pci); |
2179 | kfree(ice->spec); | ||
2173 | kfree(ice); | 2180 | kfree(ice); |
2174 | return 0; | 2181 | return 0; |
2175 | } | 2182 | } |
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 1fbe3ef8e60a..e8038c0ceb72 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -33,6 +32,11 @@ | |||
33 | #include "envy24ht.h" | 32 | #include "envy24ht.h" |
34 | #include "juli.h" | 33 | #include "juli.h" |
35 | 34 | ||
35 | struct juli_spec { | ||
36 | struct ak4114 *ak4114; | ||
37 | unsigned int analog: 1; | ||
38 | }; | ||
39 | |||
36 | /* | 40 | /* |
37 | * chip addresses on I2C bus | 41 | * chip addresses on I2C bus |
38 | */ | 42 | */ |
@@ -138,12 +142,13 @@ static struct snd_akm4xxx akm_juli_dac __devinitdata = { | |||
138 | 142 | ||
139 | static int __devinit juli_add_controls(struct snd_ice1712 *ice) | 143 | static int __devinit juli_add_controls(struct snd_ice1712 *ice) |
140 | { | 144 | { |
145 | struct juli_spec *spec = ice->spec; | ||
141 | int err; | 146 | int err; |
142 | err = snd_ice1712_akm4xxx_build_controls(ice); | 147 | err = snd_ice1712_akm4xxx_build_controls(ice); |
143 | if (err < 0) | 148 | if (err < 0) |
144 | return err; | 149 | return err; |
145 | /* only capture SPDIF over AK4114 */ | 150 | /* only capture SPDIF over AK4114 */ |
146 | err = snd_ak4114_build(ice->spec.juli.ak4114, NULL, | 151 | err = snd_ak4114_build(spec->ak4114, NULL, |
147 | ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | 152 | ice->pcm_pro->streams[SNDRV_PCM_STREAM_CAPTURE].substream); |
148 | if (err < 0) | 153 | if (err < 0) |
149 | return err; | 154 | return err; |
@@ -167,13 +172,19 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
167 | 0x41, 0x02, 0x2c, 0x00, 0x00 | 172 | 0x41, 0x02, 0x2c, 0x00, 0x00 |
168 | }; | 173 | }; |
169 | int err; | 174 | int err; |
175 | struct juli_spec *spec; | ||
170 | struct snd_akm4xxx *ak; | 176 | struct snd_akm4xxx *ak; |
171 | 177 | ||
178 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
179 | if (!spec) | ||
180 | return -ENOMEM; | ||
181 | ice->spec = spec; | ||
182 | |||
172 | err = snd_ak4114_create(ice->card, | 183 | err = snd_ak4114_create(ice->card, |
173 | juli_ak4114_read, | 184 | juli_ak4114_read, |
174 | juli_ak4114_write, | 185 | juli_ak4114_write, |
175 | ak4114_init_vals, ak4114_init_txcsb, | 186 | ak4114_init_vals, ak4114_init_txcsb, |
176 | ice, &ice->spec.juli.ak4114); | 187 | ice, &spec->ak4114); |
177 | if (err < 0) | 188 | if (err < 0) |
178 | return err; | 189 | return err; |
179 | 190 | ||
@@ -181,12 +192,12 @@ static int __devinit juli_init(struct snd_ice1712 *ice) | |||
181 | /* it seems that the analog doughter board detection does not work | 192 | /* it seems that the analog doughter board detection does not work |
182 | reliably, so force the analog flag; it should be very rare | 193 | reliably, so force the analog flag; it should be very rare |
183 | to use Juli@ without the analog doughter board */ | 194 | to use Juli@ without the analog doughter board */ |
184 | ice->spec.juli.analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1; | 195 | spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1; |
185 | #else | 196 | #else |
186 | ice->spec.juli.analog = 1; | 197 | spec->analog = 1; |
187 | #endif | 198 | #endif |
188 | 199 | ||
189 | if (ice->spec.juli.analog) { | 200 | if (spec->analog) { |
190 | printk(KERN_INFO "juli@: analog I/O detected\n"); | 201 | printk(KERN_INFO "juli@: analog I/O detected\n"); |
191 | ice->num_total_dacs = 2; | 202 | ice->num_total_dacs = 2; |
192 | ice->num_total_adcs = 2; | 203 | ice->num_total_adcs = 2; |
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 3ac25058bb58..9ab4a9f383cb 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c | |||
@@ -33,7 +33,6 @@ | |||
33 | * CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3 | 33 | * CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3 |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <sound/driver.h> | ||
37 | #include <asm/io.h> | 36 | #include <asm/io.h> |
38 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
39 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
@@ -48,6 +47,12 @@ | |||
48 | #include "phase.h" | 47 | #include "phase.h" |
49 | #include <sound/tlv.h> | 48 | #include <sound/tlv.h> |
50 | 49 | ||
50 | /* AC97 register cache for Phase28 */ | ||
51 | struct phase28_spec { | ||
52 | unsigned short master[2]; | ||
53 | unsigned short vol[8]; | ||
54 | } phase28; | ||
55 | |||
51 | /* WM8770 registers */ | 56 | /* WM8770 registers */ |
52 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ | 57 | #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ |
53 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ | 58 | #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ |
@@ -313,27 +318,32 @@ static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
313 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 318 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
314 | { | 319 | { |
315 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 320 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
321 | struct phase28_spec *spec = ice->spec; | ||
316 | int i; | 322 | int i; |
317 | for (i=0; i<2; i++) | 323 | for (i=0; i<2; i++) |
318 | ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE; | 324 | ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE; |
319 | return 0; | 325 | return 0; |
320 | } | 326 | } |
321 | 327 | ||
322 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 328 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
323 | { | 329 | { |
324 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 330 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
331 | struct phase28_spec *spec = ice->spec; | ||
325 | int ch, change = 0; | 332 | int ch, change = 0; |
326 | 333 | ||
327 | snd_ice1712_save_gpio_status(ice); | 334 | snd_ice1712_save_gpio_status(ice); |
328 | for (ch = 0; ch < 2; ch++) { | 335 | for (ch = 0; ch < 2; ch++) { |
329 | if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) { | 336 | unsigned int vol = ucontrol->value.integer.value[ch]; |
337 | if (vol > WM_VOL_MAX) | ||
338 | continue; | ||
339 | vol |= spec->master[ch] & WM_VOL_MUTE; | ||
340 | if (vol != spec->master[ch]) { | ||
330 | int dac; | 341 | int dac; |
331 | ice->spec.phase28.master[ch] &= WM_VOL_MUTE; | 342 | spec->master[ch] = vol; |
332 | ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch]; | ||
333 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 343 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
334 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, | 344 | wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, |
335 | ice->spec.phase28.vol[dac + ch], | 345 | spec->vol[dac + ch], |
336 | ice->spec.phase28.master[ch]); | 346 | spec->master[ch]); |
337 | change = 1; | 347 | change = 1; |
338 | } | 348 | } |
339 | } | 349 | } |
@@ -382,12 +392,18 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) | |||
382 | 392 | ||
383 | unsigned int tmp; | 393 | unsigned int tmp; |
384 | struct snd_akm4xxx *ak; | 394 | struct snd_akm4xxx *ak; |
395 | struct phase28_spec *spec; | ||
385 | const unsigned short *p; | 396 | const unsigned short *p; |
386 | int i; | 397 | int i; |
387 | 398 | ||
388 | ice->num_total_dacs = 8; | 399 | ice->num_total_dacs = 8; |
389 | ice->num_total_adcs = 2; | 400 | ice->num_total_adcs = 2; |
390 | 401 | ||
402 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
403 | if (!spec) | ||
404 | return -ENOMEM; | ||
405 | ice->spec = spec; | ||
406 | |||
391 | // Initialize analog chips | 407 | // Initialize analog chips |
392 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | 408 | ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); |
393 | if (!ak) | 409 | if (!ak) |
@@ -417,11 +433,11 @@ static int __devinit phase28_init(struct snd_ice1712 *ice) | |||
417 | 433 | ||
418 | snd_ice1712_restore_gpio_status(ice); | 434 | snd_ice1712_restore_gpio_status(ice); |
419 | 435 | ||
420 | ice->spec.phase28.master[0] = WM_VOL_MUTE; | 436 | spec->master[0] = WM_VOL_MUTE; |
421 | ice->spec.phase28.master[1] = WM_VOL_MUTE; | 437 | spec->master[1] = WM_VOL_MUTE; |
422 | for (i = 0; i < ice->num_total_dacs; i++) { | 438 | for (i = 0; i < ice->num_total_dacs; i++) { |
423 | ice->spec.phase28.vol[i] = WM_VOL_MUTE; | 439 | spec->vol[i] = WM_VOL_MUTE; |
424 | wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]); | 440 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
425 | } | 441 | } |
426 | 442 | ||
427 | return 0; | 443 | return 0; |
@@ -443,18 +459,21 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * | |||
443 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 459 | static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
444 | { | 460 | { |
445 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 461 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
462 | struct phase28_spec *spec = ice->spec; | ||
446 | int i, ofs, voices; | 463 | int i, ofs, voices; |
447 | 464 | ||
448 | voices = kcontrol->private_value >> 8; | 465 | voices = kcontrol->private_value >> 8; |
449 | ofs = kcontrol->private_value & 0xff; | 466 | ofs = kcontrol->private_value & 0xff; |
450 | for (i = 0; i < voices; i++) | 467 | for (i = 0; i < voices; i++) |
451 | ucontrol->value.integer.value[i] = ice->spec.phase28.vol[ofs+i] & ~WM_VOL_MUTE; | 468 | ucontrol->value.integer.value[i] = |
469 | spec->vol[ofs+i] & ~WM_VOL_MUTE; | ||
452 | return 0; | 470 | return 0; |
453 | } | 471 | } |
454 | 472 | ||
455 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 473 | static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
456 | { | 474 | { |
457 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 475 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
476 | struct phase28_spec *spec = ice->spec; | ||
458 | int i, idx, ofs, voices; | 477 | int i, idx, ofs, voices; |
459 | int change = 0; | 478 | int change = 0; |
460 | 479 | ||
@@ -462,12 +481,16 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * | |||
462 | ofs = kcontrol->private_value & 0xff; | 481 | ofs = kcontrol->private_value & 0xff; |
463 | snd_ice1712_save_gpio_status(ice); | 482 | snd_ice1712_save_gpio_status(ice); |
464 | for (i = 0; i < voices; i++) { | 483 | for (i = 0; i < voices; i++) { |
465 | idx = WM_DAC_ATTEN + ofs + i; | 484 | unsigned int vol; |
466 | if (ucontrol->value.integer.value[i] != ice->spec.phase28.vol[ofs+i]) { | 485 | vol = ucontrol->value.integer.value[i]; |
467 | ice->spec.phase28.vol[ofs+i] &= WM_VOL_MUTE; | 486 | if (vol > 0x7f) |
468 | ice->spec.phase28.vol[ofs+i] |= ucontrol->value.integer.value[i]; | 487 | continue; |
469 | wm_set_vol(ice, idx, ice->spec.phase28.vol[ofs+i], | 488 | vol |= spec->vol[ofs+i] & WM_VOL_MUTE; |
470 | ice->spec.phase28.master[i]); | 489 | if (vol != spec->vol[ofs+i]) { |
490 | spec->vol[ofs+i] = vol; | ||
491 | idx = WM_DAC_ATTEN + ofs + i; | ||
492 | wm_set_vol(ice, idx, spec->vol[ofs+i], | ||
493 | spec->master[i]); | ||
471 | change = 1; | 494 | change = 1; |
472 | } | 495 | } |
473 | } | 496 | } |
@@ -489,19 +512,22 @@ static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info | |||
489 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 512 | static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
490 | { | 513 | { |
491 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 514 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
515 | struct phase28_spec *spec = ice->spec; | ||
492 | int voices, ofs, i; | 516 | int voices, ofs, i; |
493 | 517 | ||
494 | voices = kcontrol->private_value >> 8; | 518 | voices = kcontrol->private_value >> 8; |
495 | ofs = kcontrol->private_value & 0xFF; | 519 | ofs = kcontrol->private_value & 0xFF; |
496 | 520 | ||
497 | for (i = 0; i < voices; i++) | 521 | for (i = 0; i < voices; i++) |
498 | ucontrol->value.integer.value[i] = (ice->spec.phase28.vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | 522 | ucontrol->value.integer.value[i] = |
523 | (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; | ||
499 | return 0; | 524 | return 0; |
500 | } | 525 | } |
501 | 526 | ||
502 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 527 | static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
503 | { | 528 | { |
504 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 529 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
530 | struct phase28_spec *spec = ice->spec; | ||
505 | int change = 0, voices, ofs, i; | 531 | int change = 0, voices, ofs, i; |
506 | 532 | ||
507 | voices = kcontrol->private_value >> 8; | 533 | voices = kcontrol->private_value >> 8; |
@@ -509,13 +535,13 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
509 | 535 | ||
510 | snd_ice1712_save_gpio_status(ice); | 536 | snd_ice1712_save_gpio_status(ice); |
511 | for (i = 0; i < voices; i++) { | 537 | for (i = 0; i < voices; i++) { |
512 | int val = (ice->spec.phase28.vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; | 538 | int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; |
513 | if (ucontrol->value.integer.value[i] != val) { | 539 | if (ucontrol->value.integer.value[i] != val) { |
514 | ice->spec.phase28.vol[ofs + i] &= ~WM_VOL_MUTE; | 540 | spec->vol[ofs + i] &= ~WM_VOL_MUTE; |
515 | ice->spec.phase28.vol[ofs + i] |= | 541 | spec->vol[ofs + i] |= |
516 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 542 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
517 | wm_set_vol(ice, ofs + i, ice->spec.phase28.vol[ofs + i], | 543 | wm_set_vol(ice, ofs + i, spec->vol[ofs + i], |
518 | ice->spec.phase28.master[i]); | 544 | spec->master[i]); |
519 | change = 1; | 545 | change = 1; |
520 | } | 546 | } |
521 | } | 547 | } |
@@ -532,29 +558,33 @@ static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value | |||
532 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 558 | static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
533 | { | 559 | { |
534 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 560 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
561 | struct phase28_spec *spec = ice->spec; | ||
535 | 562 | ||
536 | ucontrol->value.integer.value[0] = (ice->spec.phase28.master[0] & WM_VOL_MUTE) ? 0 : 1; | 563 | ucontrol->value.integer.value[0] = |
537 | ucontrol->value.integer.value[1] = (ice->spec.phase28.master[1] & WM_VOL_MUTE) ? 0 : 1; | 564 | (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; |
565 | ucontrol->value.integer.value[1] = | ||
566 | (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; | ||
538 | return 0; | 567 | return 0; |
539 | } | 568 | } |
540 | 569 | ||
541 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 570 | static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
542 | { | 571 | { |
543 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 572 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
573 | struct phase28_spec *spec = ice->spec; | ||
544 | int change = 0, i; | 574 | int change = 0, i; |
545 | 575 | ||
546 | snd_ice1712_save_gpio_status(ice); | 576 | snd_ice1712_save_gpio_status(ice); |
547 | for (i = 0; i < 2; i++) { | 577 | for (i = 0; i < 2; i++) { |
548 | int val = (ice->spec.phase28.master[i] & WM_VOL_MUTE) ? 0 : 1; | 578 | int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; |
549 | if (ucontrol->value.integer.value[i] != val) { | 579 | if (ucontrol->value.integer.value[i] != val) { |
550 | int dac; | 580 | int dac; |
551 | ice->spec.phase28.master[i] &= ~WM_VOL_MUTE; | 581 | spec->master[i] &= ~WM_VOL_MUTE; |
552 | ice->spec.phase28.master[i] |= | 582 | spec->master[i] |= |
553 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; | 583 | ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; |
554 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) | 584 | for (dac = 0; dac < ice->num_total_dacs; dac += 2) |
555 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, | 585 | wm_set_vol(ice, WM_DAC_ATTEN + dac + i, |
556 | ice->spec.phase28.vol[dac + i], | 586 | spec->vol[dac + i], |
557 | ice->spec.phase28.master[i]); | 587 | spec->master[i]); |
558 | change = 1; | 588 | change = 1; |
559 | } | 589 | } |
560 | } | 590 | } |
@@ -595,8 +625,10 @@ static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_val | |||
595 | unsigned short ovol, nvol; | 625 | unsigned short ovol, nvol; |
596 | int change = 0; | 626 | int change = 0; |
597 | 627 | ||
598 | snd_ice1712_save_gpio_status(ice); | ||
599 | nvol = ucontrol->value.integer.value[0]; | 628 | nvol = ucontrol->value.integer.value[0]; |
629 | if (nvol > PCM_RES) | ||
630 | return -EINVAL; | ||
631 | snd_ice1712_save_gpio_status(ice); | ||
600 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; | 632 | nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; |
601 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; | 633 | ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; |
602 | if (ovol != nvol) { | 634 | if (ovol != nvol) { |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index faefd52c1b80..4945c81e8a96 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 4180f9739ecb..48cf40a8f32a 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -54,7 +54,6 @@ | |||
54 | * | 54 | * |
55 | */ | 55 | */ |
56 | 56 | ||
57 | #include <sound/driver.h> | ||
58 | #include <asm/io.h> | 57 | #include <asm/io.h> |
59 | #include <linux/delay.h> | 58 | #include <linux/delay.h> |
60 | #include <linux/interrupt.h> | 59 | #include <linux/interrupt.h> |
@@ -68,6 +67,12 @@ | |||
68 | #include "stac946x.h" | 67 | #include "stac946x.h" |
69 | #include <sound/tlv.h> | 68 | #include <sound/tlv.h> |
70 | 69 | ||
70 | struct prodigy192_spec { | ||
71 | struct ak4114 *ak4114; | ||
72 | /* rate change needs atomic mute/unmute of all dacs*/ | ||
73 | struct mutex mute_mutex; | ||
74 | }; | ||
75 | |||
71 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) | 76 | static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) |
72 | { | 77 | { |
73 | snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); | 78 | snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); |
@@ -81,6 +86,24 @@ static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) | |||
81 | /* | 86 | /* |
82 | * DAC mute control | 87 | * DAC mute control |
83 | */ | 88 | */ |
89 | |||
90 | /* | ||
91 | * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute | ||
92 | */ | ||
93 | static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, | ||
94 | unsigned char mute) | ||
95 | { | ||
96 | unsigned char new, old; | ||
97 | int change; | ||
98 | old = stac9460_get(ice, idx); | ||
99 | new = (~mute << 7 & 0x80) | (old & ~0x80); | ||
100 | change = (new != old); | ||
101 | if (change) | ||
102 | /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/ | ||
103 | stac9460_put(ice, idx, new); | ||
104 | return change; | ||
105 | } | ||
106 | |||
84 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info | 107 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info |
85 | 108 | ||
86 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 109 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
@@ -101,20 +124,19 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
101 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 124 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
102 | { | 125 | { |
103 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 126 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
104 | unsigned char new, old; | 127 | struct prodigy192_spec *spec = ice->spec; |
105 | int idx; | 128 | int idx, change; |
106 | int change; | ||
107 | 129 | ||
108 | if (kcontrol->private_value) | 130 | if (kcontrol->private_value) |
109 | idx = STAC946X_MASTER_VOLUME; | 131 | idx = STAC946X_MASTER_VOLUME; |
110 | else | 132 | else |
111 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | 133 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; |
112 | old = stac9460_get(ice, idx); | 134 | /* due to possible conflicts with stac9460_set_rate_val, mutexing */ |
113 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); | 135 | mutex_lock(&spec->mute_mutex); |
114 | change = (new != old); | 136 | /*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, |
115 | if (change) | 137 | ucontrol->value.integer.value[0]);*/ |
116 | stac9460_put(ice, idx, new); | 138 | change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); |
117 | 139 | mutex_unlock(&spec->mute_mutex); | |
118 | return change; | 140 | return change; |
119 | } | 141 | } |
120 | 142 | ||
@@ -162,6 +184,8 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
162 | ovol = 0x7f - (tmp & 0x7f); | 184 | ovol = 0x7f - (tmp & 0x7f); |
163 | change = (ovol != nvol); | 185 | change = (ovol != nvol); |
164 | if (change) { | 186 | if (change) { |
187 | ovol = (0x7f - nvol) | (tmp & 0x80); | ||
188 | /*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/ | ||
165 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); | 189 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); |
166 | } | 190 | } |
167 | return change; | 191 | return change; |
@@ -241,7 +265,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
241 | 265 | ||
242 | for (i = 0; i < 2; ++i) { | 266 | for (i = 0; i < 2; ++i) { |
243 | reg = STAC946X_MIC_L_VOLUME + i; | 267 | reg = STAC946X_MIC_L_VOLUME + i; |
244 | nvol = ucontrol->value.integer.value[i]; | 268 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
245 | ovol = 0x0f - stac9460_get(ice, reg); | 269 | ovol = 0x0f - stac9460_get(ice, reg); |
246 | change = ((ovol & 0x0f) != nvol); | 270 | change = ((ovol & 0x0f) != nvol); |
247 | if (change) | 271 | if (change) |
@@ -251,121 +275,6 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
251 | return change; | 275 | return change; |
252 | } | 276 | } |
253 | 277 | ||
254 | #if 0 | ||
255 | /* | ||
256 | * Headphone Amplifier | ||
257 | */ | ||
258 | static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) | ||
259 | { | ||
260 | unsigned int tmp, tmp2; | ||
261 | |||
262 | tmp2 = tmp = snd_ice1712_gpio_read(ice); | ||
263 | if (enable) | ||
264 | tmp |= AUREON_HP_SEL; | ||
265 | else | ||
266 | tmp &= ~ AUREON_HP_SEL; | ||
267 | if (tmp != tmp2) { | ||
268 | snd_ice1712_gpio_write(ice, tmp); | ||
269 | return 1; | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int aureon_get_headphone_amp(struct snd_ice1712 *ice) | ||
275 | { | ||
276 | unsigned int tmp = snd_ice1712_gpio_read(ice); | ||
277 | |||
278 | return ( tmp & AUREON_HP_SEL )!= 0; | ||
279 | } | ||
280 | |||
281 | #define aureon_bool_info snd_ctl_boolean_mono_info | ||
282 | |||
283 | static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
286 | |||
287 | ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | |||
292 | static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
293 | { | ||
294 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
295 | |||
296 | return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Deemphasis | ||
301 | */ | ||
302 | static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
303 | { | ||
304 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
305 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
310 | { | ||
311 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
312 | int temp, temp2; | ||
313 | temp2 = temp = wm_get(ice, WM_DAC_CTRL2); | ||
314 | if (ucontrol->value.integer.value[0]) | ||
315 | temp |= 0xf; | ||
316 | else | ||
317 | temp &= ~0xf; | ||
318 | if (temp != temp2) { | ||
319 | wm_put(ice, WM_DAC_CTRL2, temp); | ||
320 | return 1; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * ADC Oversampling | ||
327 | */ | ||
328 | static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) | ||
329 | { | ||
330 | static char *texts[2] = { "128x", "64x" }; | ||
331 | |||
332 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
333 | uinfo->count = 1; | ||
334 | uinfo->value.enumerated.items = 2; | ||
335 | |||
336 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
337 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
338 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
344 | { | ||
345 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
346 | ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
351 | { | ||
352 | int temp, temp2; | ||
353 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
354 | |||
355 | temp2 = temp = wm_get(ice, WM_MASTER); | ||
356 | |||
357 | if (ucontrol->value.enumerated.item[0]) | ||
358 | temp |= 0x8; | ||
359 | else | ||
360 | temp &= ~0x8; | ||
361 | |||
362 | if (temp != temp2) { | ||
363 | wm_put(ice, WM_MASTER, temp); | ||
364 | return 1; | ||
365 | } | ||
366 | return 0; | ||
367 | } | ||
368 | #endif | ||
369 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, | 278 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, |
370 | struct snd_ctl_elem_info *uinfo) | 279 | struct snd_ctl_elem_info *uinfo) |
371 | { | 280 | { |
@@ -407,6 +316,57 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |||
407 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | 316 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); |
408 | return change; | 317 | return change; |
409 | } | 318 | } |
319 | /* | ||
320 | * Handler for setting correct codec rate - called when rate change is detected | ||
321 | */ | ||
322 | static void stac9460_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | ||
323 | { | ||
324 | unsigned char old, new; | ||
325 | int idx; | ||
326 | unsigned char changed[7]; | ||
327 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
328 | struct prodigy192_spec *spec = ice->spec; | ||
329 | |||
330 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | ||
331 | return; | ||
332 | else if (rate <= 48000) | ||
333 | new = 0x08; /* 256x, base rate mode */ | ||
334 | else if (rate <= 96000) | ||
335 | new = 0x11; /* 256x, mid rate mode */ | ||
336 | else | ||
337 | new = 0x12; /* 128x, high rate mode */ | ||
338 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | ||
339 | if (old == new) | ||
340 | return; | ||
341 | /* change detected, setting master clock, muting first */ | ||
342 | /* due to possible conflicts with mute controls - mutexing */ | ||
343 | mutex_lock(&spec->mute_mutex); | ||
344 | /* we have to remember current mute status for each DAC */ | ||
345 | for (idx = 0; idx < 7 ; ++idx) | ||
346 | changed[idx] = stac9460_dac_mute(ice, | ||
347 | STAC946X_MASTER_VOLUME + idx, 0); | ||
348 | /*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/ | ||
349 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); | ||
350 | udelay(10); | ||
351 | /* unmuting - only originally unmuted dacs - | ||
352 | * i.e. those changed when muting */ | ||
353 | for (idx = 0; idx < 7 ; ++idx) { | ||
354 | if (changed[idx]) | ||
355 | stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); | ||
356 | } | ||
357 | mutex_unlock(&spec->mute_mutex); | ||
358 | } | ||
359 | |||
360 | /* using akm infrastructure for setting rate of the codec */ | ||
361 | static struct snd_akm4xxx akmlike_stac9460 __devinitdata = { | ||
362 | .type = NON_AKM, /* special value */ | ||
363 | .num_adcs = 6, /* not used in any way, just for completeness */ | ||
364 | .num_dacs = 2, | ||
365 | .ops = { | ||
366 | .set_rate_val = stac9460_set_rate_val | ||
367 | } | ||
368 | }; | ||
369 | |||
410 | 370 | ||
411 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | 371 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
412 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | 372 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); |
@@ -483,39 +443,8 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
483 | .put = stac9460_mic_sw_put, | 443 | .put = stac9460_mic_sw_put, |
484 | 444 | ||
485 | }, | 445 | }, |
486 | #if 0 | ||
487 | { | ||
488 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
489 | .name = "Capture Route", | ||
490 | .info = wm_adc_mux_info, | ||
491 | .get = wm_adc_mux_get, | ||
492 | .put = wm_adc_mux_put, | ||
493 | }, | ||
494 | { | ||
495 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
496 | .name = "Headphone Amplifier Switch", | ||
497 | .info = aureon_bool_info, | ||
498 | .get = aureon_hpamp_get, | ||
499 | .put = aureon_hpamp_put | ||
500 | }, | ||
501 | { | ||
502 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
503 | .name = "DAC Deemphasis Switch", | ||
504 | .info = aureon_bool_info, | ||
505 | .get = aureon_deemp_get, | ||
506 | .put = aureon_deemp_put | ||
507 | }, | ||
508 | { | ||
509 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
510 | .name = "ADC Oversampling", | ||
511 | .info = aureon_oversampling_info, | ||
512 | .get = aureon_oversampling_get, | ||
513 | .put = aureon_oversampling_put | ||
514 | }, | ||
515 | #endif | ||
516 | }; | 446 | }; |
517 | 447 | ||
518 | |||
519 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ | 448 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ |
520 | /* CDTO (pin 32) -- GPIO11 pin 86 | 449 | /* CDTO (pin 32) -- GPIO11 pin 86 |
521 | * CDTI (pin 33) -- GPIO10 pin 77 | 450 | * CDTI (pin 33) -- GPIO10 pin 77 |
@@ -712,16 +641,39 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
712 | static const unsigned char ak4114_init_txcsb[] = { | 641 | static const unsigned char ak4114_init_txcsb[] = { |
713 | 0x41, 0x02, 0x2c, 0x00, 0x00 | 642 | 0x41, 0x02, 0x2c, 0x00, 0x00 |
714 | }; | 643 | }; |
644 | struct prodigy192_spec *spec = ice->spec; | ||
715 | 645 | ||
716 | return snd_ak4114_create(ice->card, | 646 | return snd_ak4114_create(ice->card, |
717 | prodigy192_ak4114_read, | 647 | prodigy192_ak4114_read, |
718 | prodigy192_ak4114_write, | 648 | prodigy192_ak4114_write, |
719 | ak4114_init_vals, ak4114_init_txcsb, | 649 | ak4114_init_vals, ak4114_init_txcsb, |
720 | ice, &ice->spec.prodigy192.ak4114); | 650 | ice, &spec->ak4114); |
651 | } | ||
652 | |||
653 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | ||
654 | struct snd_info_buffer *buffer) | ||
655 | { | ||
656 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | ||
657 | int reg, val; | ||
658 | /* registers 0x0 - 0x14 */ | ||
659 | for (reg = 0; reg <= 0x15; reg++) { | ||
660 | val = stac9460_get(ice, reg); | ||
661 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | ||
662 | } | ||
663 | } | ||
664 | |||
665 | |||
666 | static void stac9460_proc_init(struct snd_ice1712 *ice) | ||
667 | { | ||
668 | struct snd_info_entry *entry; | ||
669 | if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) | ||
670 | snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); | ||
721 | } | 671 | } |
722 | 672 | ||
673 | |||
723 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | 674 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) |
724 | { | 675 | { |
676 | struct prodigy192_spec *spec = ice->spec; | ||
725 | unsigned int i; | 677 | unsigned int i; |
726 | int err; | 678 | int err; |
727 | 679 | ||
@@ -731,7 +683,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
731 | if (err < 0) | 683 | if (err < 0) |
732 | return err; | 684 | return err; |
733 | } | 685 | } |
734 | if (ice->spec.prodigy192.ak4114) { | 686 | if (spec->ak4114) { |
735 | /* ak4114 is connected */ | 687 | /* ak4114 is connected */ |
736 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { | 688 | for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { |
737 | err = snd_ctl_add(ice->card, | 689 | err = snd_ctl_add(ice->card, |
@@ -740,12 +692,13 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
740 | if (err < 0) | 692 | if (err < 0) |
741 | return err; | 693 | return err; |
742 | } | 694 | } |
743 | err = snd_ak4114_build(ice->spec.prodigy192.ak4114, | 695 | err = snd_ak4114_build(spec->ak4114, |
744 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ | 696 | NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ |
745 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | 697 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); |
746 | if (err < 0) | 698 | if (err < 0) |
747 | return err; | 699 | return err; |
748 | } | 700 | } |
701 | stac9460_proc_init(ice); | ||
749 | return 0; | 702 | return 0; |
750 | } | 703 | } |
751 | 704 | ||
@@ -778,6 +731,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
778 | { | 731 | { |
779 | static const unsigned short stac_inits_prodigy[] = { | 732 | static const unsigned short stac_inits_prodigy[] = { |
780 | STAC946X_RESET, 0, | 733 | STAC946X_RESET, 0, |
734 | STAC946X_MASTER_CLOCKING, 0x11, | ||
781 | /* STAC946X_MASTER_VOLUME, 0, | 735 | /* STAC946X_MASTER_VOLUME, 0, |
782 | STAC946X_LF_VOLUME, 0, | 736 | STAC946X_LF_VOLUME, 0, |
783 | STAC946X_RF_VOLUME, 0, | 737 | STAC946X_RF_VOLUME, 0, |
@@ -789,22 +743,39 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
789 | }; | 743 | }; |
790 | const unsigned short *p; | 744 | const unsigned short *p; |
791 | int err = 0; | 745 | int err = 0; |
746 | struct snd_akm4xxx *ak; | ||
747 | struct prodigy192_spec *spec; | ||
792 | 748 | ||
793 | /* prodigy 192 */ | 749 | /* prodigy 192 */ |
794 | ice->num_total_dacs = 6; | 750 | ice->num_total_dacs = 6; |
795 | ice->num_total_adcs = 2; | 751 | ice->num_total_adcs = 2; |
796 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ | 752 | ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ |
797 | 753 | ||
754 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
755 | if (!spec) | ||
756 | return -ENOMEM; | ||
757 | ice->spec = spec; | ||
758 | mutex_init(&spec->mute_mutex); | ||
759 | |||
798 | /* initialize codec */ | 760 | /* initialize codec */ |
799 | p = stac_inits_prodigy; | 761 | p = stac_inits_prodigy; |
800 | for (; *p != (unsigned short)-1; p += 2) | 762 | for (; *p != (unsigned short)-1; p += 2) |
801 | stac9460_put(ice, p[0], p[1]); | 763 | stac9460_put(ice, p[0], p[1]); |
764 | /* reusing the akm codecs infrastructure, | ||
765 | * for setting rate on stac9460 */ | ||
766 | ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
767 | if (!ak) | ||
768 | return -ENOMEM; | ||
769 | ice->akm_codecs = 1; | ||
770 | err = snd_ice1712_akm4xxx_init(ak, &akmlike_stac9460, NULL, ice); | ||
771 | if (err < 0) | ||
772 | return err; | ||
802 | 773 | ||
803 | /* MI/ODI/O add on card with AK4114 */ | 774 | /* MI/ODI/O add on card with AK4114 */ |
804 | if (prodigy192_miodio_exists(ice)) { | 775 | if (prodigy192_miodio_exists(ice)) { |
805 | err = prodigy192_ak4114_init(ice); | 776 | err = prodigy192_ak4114_init(ice); |
806 | /* from this moment if err = 0 then | 777 | /* from this moment if err = 0 then |
807 | * ice->spec.prodigy192.ak4114 should not be null | 778 | * spec->ak4114 should not be null |
808 | */ | 779 | */ |
809 | snd_printdd("AK4114 initialized with status %d\n", err); | 780 | snd_printdd("AK4114 initialized with status %d\n", err); |
810 | } else | 781 | } else |
@@ -854,6 +825,10 @@ struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { | |||
854 | .build_controls = prodigy192_add_controls, | 825 | .build_controls = prodigy192_add_controls, |
855 | .eeprom_size = sizeof(prodigy71_eeprom), | 826 | .eeprom_size = sizeof(prodigy71_eeprom), |
856 | .eeprom_data = prodigy71_eeprom, | 827 | .eeprom_data = prodigy71_eeprom, |
828 | /* the current MPU401 code loops infinitely | ||
829 | * when opening midi device | ||
830 | */ | ||
831 | .no_mpu401 = 1, | ||
857 | }, | 832 | }, |
858 | { } /* terminator */ | 833 | { } /* terminator */ |
859 | }; | 834 | }; |
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c new file mode 100644 index 000000000000..043a93879bd5 --- /dev/null +++ b/sound/pci/ice1712/prodigy_hifi.c | |||
@@ -0,0 +1,1210 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi | ||
5 | * based on pontis.c | ||
6 | * | ||
7 | * Copyright (c) 2007 Julian Scheel <julian@jusst.de> | ||
8 | * Copyright (c) 2007 allank | ||
9 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | |||
28 | #include <asm/io.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/mutex.h> | ||
34 | |||
35 | #include <sound/core.h> | ||
36 | #include <sound/info.h> | ||
37 | #include <sound/tlv.h> | ||
38 | |||
39 | #include "ice1712.h" | ||
40 | #include "envy24ht.h" | ||
41 | #include "prodigy_hifi.h" | ||
42 | |||
43 | struct prodigy_hifi_spec { | ||
44 | unsigned short master[2]; | ||
45 | unsigned short vol[8]; | ||
46 | }; | ||
47 | |||
48 | /* I2C addresses */ | ||
49 | #define WM_DEV 0x34 | ||
50 | |||
51 | /* WM8776 registers */ | ||
52 | #define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ | ||
53 | #define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ | ||
54 | #define WM_HP_MASTER 0x02 /* headphone master (both channels), | ||
55 | override LLR */ | ||
56 | #define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ | ||
57 | #define WM_DAC_ATTEN_R 0x04 | ||
58 | #define WM_DAC_MASTER 0x05 | ||
59 | #define WM_PHASE_SWAP 0x06 /* DAC phase swap */ | ||
60 | #define WM_DAC_CTRL1 0x07 | ||
61 | #define WM_DAC_MUTE 0x08 | ||
62 | #define WM_DAC_CTRL2 0x09 | ||
63 | #define WM_DAC_INT 0x0a | ||
64 | #define WM_ADC_INT 0x0b | ||
65 | #define WM_MASTER_CTRL 0x0c | ||
66 | #define WM_POWERDOWN 0x0d | ||
67 | #define WM_ADC_ATTEN_L 0x0e | ||
68 | #define WM_ADC_ATTEN_R 0x0f | ||
69 | #define WM_ALC_CTRL1 0x10 | ||
70 | #define WM_ALC_CTRL2 0x11 | ||
71 | #define WM_ALC_CTRL3 0x12 | ||
72 | #define WM_NOISE_GATE 0x13 | ||
73 | #define WM_LIMITER 0x14 | ||
74 | #define WM_ADC_MUX 0x15 | ||
75 | #define WM_OUT_MUX 0x16 | ||
76 | #define WM_RESET 0x17 | ||
77 | |||
78 | /* Analog Recording Source :- Mic, LineIn, CD/Video, */ | ||
79 | |||
80 | /* implement capture source select control for WM8776 */ | ||
81 | |||
82 | #define WM_AIN1 "AIN1" | ||
83 | #define WM_AIN2 "AIN2" | ||
84 | #define WM_AIN3 "AIN3" | ||
85 | #define WM_AIN4 "AIN4" | ||
86 | #define WM_AIN5 "AIN5" | ||
87 | |||
88 | /* GPIO pins of envy24ht connected to wm8766 */ | ||
89 | #define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */ | ||
90 | #define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */ | ||
91 | #define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */ | ||
92 | |||
93 | /* WM8766 registers */ | ||
94 | #define WM8766_DAC_CTRL 0x02 /* DAC Control */ | ||
95 | #define WM8766_INT_CTRL 0x03 /* Interface Control */ | ||
96 | #define WM8766_DAC_CTRL2 0x09 | ||
97 | #define WM8766_DAC_CTRL3 0x0a | ||
98 | #define WM8766_RESET 0x1f | ||
99 | #define WM8766_LDA1 0x00 | ||
100 | #define WM8766_LDA2 0x04 | ||
101 | #define WM8766_LDA3 0x06 | ||
102 | #define WM8766_RDA1 0x01 | ||
103 | #define WM8766_RDA2 0x05 | ||
104 | #define WM8766_RDA3 0x07 | ||
105 | #define WM8766_MUTE1 0x0C | ||
106 | #define WM8766_MUTE2 0x0F | ||
107 | |||
108 | |||
109 | /* | ||
110 | * Prodigy HD2 | ||
111 | */ | ||
112 | #define AK4396_ADDR 0x00 | ||
113 | #define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */ | ||
114 | #define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */ | ||
115 | #define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */ | ||
116 | |||
117 | /* ak4396 registers */ | ||
118 | #define AK4396_CTRL1 0x00 | ||
119 | #define AK4396_CTRL2 0x01 | ||
120 | #define AK4396_CTRL3 0x02 | ||
121 | #define AK4396_LCH_ATT 0x03 | ||
122 | #define AK4396_RCH_ATT 0x04 | ||
123 | |||
124 | |||
125 | /* | ||
126 | * get the current register value of WM codec | ||
127 | */ | ||
128 | static unsigned short wm_get(struct snd_ice1712 *ice, int reg) | ||
129 | { | ||
130 | reg <<= 1; | ||
131 | return ((unsigned short)ice->akm[0].images[reg] << 8) | | ||
132 | ice->akm[0].images[reg + 1]; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * set the register value of WM codec and remember it | ||
137 | */ | ||
138 | static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) | ||
139 | { | ||
140 | unsigned short cval; | ||
141 | cval = (reg << 9) | val; | ||
142 | snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); | ||
143 | } | ||
144 | |||
145 | static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) | ||
146 | { | ||
147 | wm_put_nocache(ice, reg, val); | ||
148 | reg <<= 1; | ||
149 | ice->akm[0].images[reg] = val >> 8; | ||
150 | ice->akm[0].images[reg + 1] = val; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * write data in the SPI mode | ||
155 | */ | ||
156 | |||
157 | static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) | ||
158 | { | ||
159 | unsigned int tmp = snd_ice1712_gpio_read(ice); | ||
160 | if (val) | ||
161 | tmp |= bit; | ||
162 | else | ||
163 | tmp &= ~bit; | ||
164 | snd_ice1712_gpio_write(ice, tmp); | ||
165 | } | ||
166 | |||
167 | /* | ||
168 | * SPI implementation for WM8766 codec - only writing supported, no readback | ||
169 | */ | ||
170 | |||
171 | static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data) | ||
172 | { | ||
173 | int i; | ||
174 | for (i = 0; i < 16; i++) { | ||
175 | set_gpio_bit(ice, WM8766_SPI_CLK, 0); | ||
176 | udelay(1); | ||
177 | set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000); | ||
178 | udelay(1); | ||
179 | set_gpio_bit(ice, WM8766_SPI_CLK, 1); | ||
180 | udelay(1); | ||
181 | data <<= 1; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg, | ||
186 | unsigned int data) | ||
187 | { | ||
188 | unsigned int block; | ||
189 | |||
190 | snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD| | ||
191 | WM8766_SPI_CLK|WM8766_SPI_ML); | ||
192 | snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD| | ||
193 | WM8766_SPI_CLK|WM8766_SPI_ML)); | ||
194 | /* latch must be low when writing */ | ||
195 | set_gpio_bit(ice, WM8766_SPI_ML, 0); | ||
196 | block = (reg << 9) | (data & 0x1ff); | ||
197 | wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */ | ||
198 | /* release latch */ | ||
199 | set_gpio_bit(ice, WM8766_SPI_ML, 1); | ||
200 | udelay(1); | ||
201 | /* restore */ | ||
202 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | ||
203 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
204 | } | ||
205 | |||
206 | |||
207 | /* | ||
208 | * serial interface for ak4396 - only writing supported, no readback | ||
209 | */ | ||
210 | |||
211 | static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data) | ||
212 | { | ||
213 | int i; | ||
214 | for (i = 0; i < 16; i++) { | ||
215 | set_gpio_bit(ice, AK4396_CCLK, 0); | ||
216 | udelay(1); | ||
217 | set_gpio_bit(ice, AK4396_CDTI, data & 0x8000); | ||
218 | udelay(1); | ||
219 | set_gpio_bit(ice, AK4396_CCLK, 1); | ||
220 | udelay(1); | ||
221 | data <<= 1; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg, | ||
226 | unsigned int data) | ||
227 | { | ||
228 | unsigned int block; | ||
229 | |||
230 | snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI); | ||
231 | snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI)); | ||
232 | /* latch must be low when writing */ | ||
233 | set_gpio_bit(ice, AK4396_CSN, 0); | ||
234 | block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) | | ||
235 | ((reg & 0x1f) << 8) | (data & 0xff); | ||
236 | ak4396_send_word(ice, block); /* REGISTER ADDRESS */ | ||
237 | /* release latch */ | ||
238 | set_gpio_bit(ice, AK4396_CSN, 1); | ||
239 | udelay(1); | ||
240 | /* restore */ | ||
241 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | ||
242 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | ||
243 | } | ||
244 | |||
245 | |||
246 | /* | ||
247 | * ak4396 mixers | ||
248 | */ | ||
249 | |||
250 | |||
251 | |||
252 | /* | ||
253 | * DAC volume attenuation mixer control (-64dB to 0dB) | ||
254 | */ | ||
255 | |||
256 | static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol, | ||
257 | struct snd_ctl_elem_info *uinfo) | ||
258 | { | ||
259 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
260 | uinfo->count = 2; | ||
261 | uinfo->value.integer.min = 0; /* mute */ | ||
262 | uinfo->value.integer.max = 0xFF; /* linear */ | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol, | ||
267 | struct snd_ctl_elem_value *ucontrol) | ||
268 | { | ||
269 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
270 | struct prodigy_hifi_spec *spec = ice->spec; | ||
271 | int i; | ||
272 | |||
273 | for (i = 0; i < 2; i++) | ||
274 | ucontrol->value.integer.value[i] = spec->vol[i]; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
280 | { | ||
281 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
282 | struct prodigy_hifi_spec *spec = ice->spec; | ||
283 | int i; | ||
284 | int change = 0; | ||
285 | |||
286 | mutex_lock(&ice->gpio_mutex); | ||
287 | for (i = 0; i < 2; i++) { | ||
288 | if (ucontrol->value.integer.value[i] != spec->vol[i]) { | ||
289 | spec->vol[i] = ucontrol->value.integer.value[i]; | ||
290 | ak4396_write(ice, AK4396_LCH_ATT + i, | ||
291 | spec->vol[i] & 0xff); | ||
292 | change = 1; | ||
293 | } | ||
294 | } | ||
295 | mutex_unlock(&ice->gpio_mutex); | ||
296 | return change; | ||
297 | } | ||
298 | |||
299 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | ||
300 | |||
301 | static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { | ||
302 | { | ||
303 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
304 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
305 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
306 | .name = "Front Playback Volume", | ||
307 | .info = ak4396_dac_vol_info, | ||
308 | .get = ak4396_dac_vol_get, | ||
309 | .put = ak4396_dac_vol_put, | ||
310 | .tlv = { .p = db_scale_wm_dac }, | ||
311 | }, | ||
312 | }; | ||
313 | |||
314 | |||
315 | /* --------------- */ | ||
316 | |||
317 | /* | ||
318 | * Logarithmic volume values for WM87*6 | ||
319 | * Computed as 20 * Log10(255 / x) | ||
320 | */ | ||
321 | static const unsigned char wm_vol[256] = { | ||
322 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | ||
323 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | ||
324 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | ||
325 | 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, | ||
326 | 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, | ||
327 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, | ||
328 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | ||
329 | 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, | ||
330 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | ||
331 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | ||
332 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
333 | 0, 0 | ||
334 | }; | ||
335 | |||
336 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) | ||
337 | #define WM_VOL_MUTE 0x8000 | ||
338 | |||
339 | |||
340 | #define DAC_0dB 0xff | ||
341 | #define DAC_RES 128 | ||
342 | #define DAC_MIN (DAC_0dB - DAC_RES) | ||
343 | |||
344 | |||
345 | static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, | ||
346 | unsigned short vol, unsigned short master) | ||
347 | { | ||
348 | unsigned char nvol; | ||
349 | |||
350 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | ||
351 | nvol = 0; | ||
352 | else { | ||
353 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | ||
354 | & WM_VOL_MAX; | ||
355 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | ||
356 | } | ||
357 | |||
358 | wm_put(ice, index, nvol); | ||
359 | wm_put_nocache(ice, index, 0x100 | nvol); | ||
360 | } | ||
361 | |||
362 | static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index, | ||
363 | unsigned short vol, unsigned short master) | ||
364 | { | ||
365 | unsigned char nvol; | ||
366 | |||
367 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | ||
368 | nvol = 0; | ||
369 | else { | ||
370 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | ||
371 | & WM_VOL_MAX; | ||
372 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | ||
373 | } | ||
374 | |||
375 | wm8766_spi_write(ice, index, (0x0100 | nvol)); | ||
376 | } | ||
377 | |||
378 | |||
379 | /* | ||
380 | * DAC volume attenuation mixer control (-64dB to 0dB) | ||
381 | */ | ||
382 | |||
383 | static int wm_dac_vol_info(struct snd_kcontrol *kcontrol, | ||
384 | struct snd_ctl_elem_info *uinfo) | ||
385 | { | ||
386 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
387 | uinfo->count = 2; | ||
388 | uinfo->value.integer.min = 0; /* mute */ | ||
389 | uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, | ||
394 | struct snd_ctl_elem_value *ucontrol) | ||
395 | { | ||
396 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
397 | struct prodigy_hifi_spec *spec = ice->spec; | ||
398 | int i; | ||
399 | |||
400 | for (i = 0; i < 2; i++) | ||
401 | ucontrol->value.integer.value[i] = | ||
402 | spec->vol[2 + i] & ~WM_VOL_MUTE; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
407 | { | ||
408 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
409 | struct prodigy_hifi_spec *spec = ice->spec; | ||
410 | int i, idx, change = 0; | ||
411 | |||
412 | mutex_lock(&ice->gpio_mutex); | ||
413 | for (i = 0; i < 2; i++) { | ||
414 | if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) { | ||
415 | idx = WM_DAC_ATTEN_L + i; | ||
416 | spec->vol[2 + i] &= WM_VOL_MUTE; | ||
417 | spec->vol[2 + i] |= ucontrol->value.integer.value[i]; | ||
418 | wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]); | ||
419 | change = 1; | ||
420 | } | ||
421 | } | ||
422 | mutex_unlock(&ice->gpio_mutex); | ||
423 | return change; | ||
424 | } | ||
425 | |||
426 | |||
427 | /* | ||
428 | * WM8766 DAC volume attenuation mixer control | ||
429 | */ | ||
430 | static int wm8766_vol_info(struct snd_kcontrol *kcontrol, | ||
431 | struct snd_ctl_elem_info *uinfo) | ||
432 | { | ||
433 | int voices = kcontrol->private_value >> 8; | ||
434 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
435 | uinfo->count = voices; | ||
436 | uinfo->value.integer.min = 0; /* mute */ | ||
437 | uinfo->value.integer.max = DAC_RES; /* 0dB */ | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int wm8766_vol_get(struct snd_kcontrol *kcontrol, | ||
442 | struct snd_ctl_elem_value *ucontrol) | ||
443 | { | ||
444 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
445 | struct prodigy_hifi_spec *spec = ice->spec; | ||
446 | int i, ofs, voices; | ||
447 | |||
448 | voices = kcontrol->private_value >> 8; | ||
449 | ofs = kcontrol->private_value & 0xff; | ||
450 | for (i = 0; i < voices; i++) | ||
451 | ucontrol->value.integer.value[i] = spec->vol[ofs + i]; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
456 | { | ||
457 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
458 | struct prodigy_hifi_spec *spec = ice->spec; | ||
459 | int i, idx, ofs, voices; | ||
460 | int change = 0; | ||
461 | |||
462 | voices = kcontrol->private_value >> 8; | ||
463 | ofs = kcontrol->private_value & 0xff; | ||
464 | mutex_lock(&ice->gpio_mutex); | ||
465 | for (i = 0; i < voices; i++) { | ||
466 | if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) { | ||
467 | idx = WM8766_LDA1 + ofs + i; | ||
468 | spec->vol[ofs + i] &= WM_VOL_MUTE; | ||
469 | spec->vol[ofs + i] |= ucontrol->value.integer.value[i]; | ||
470 | wm8766_set_vol(ice, idx, | ||
471 | spec->vol[ofs + i], spec->master[i]); | ||
472 | change = 1; | ||
473 | } | ||
474 | } | ||
475 | mutex_unlock(&ice->gpio_mutex); | ||
476 | return change; | ||
477 | } | ||
478 | |||
479 | /* | ||
480 | * Master volume attenuation mixer control / applied to WM8776+WM8766 | ||
481 | */ | ||
482 | static int wm_master_vol_info(struct snd_kcontrol *kcontrol, | ||
483 | struct snd_ctl_elem_info *uinfo) | ||
484 | { | ||
485 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
486 | uinfo->count = 2; | ||
487 | uinfo->value.integer.min = 0; | ||
488 | uinfo->value.integer.max = DAC_RES; | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, | ||
493 | struct snd_ctl_elem_value *ucontrol) | ||
494 | { | ||
495 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
496 | struct prodigy_hifi_spec *spec = ice->spec; | ||
497 | int i; | ||
498 | for (i = 0; i < 2; i++) | ||
499 | ucontrol->value.integer.value[i] = spec->master[i]; | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, | ||
504 | struct snd_ctl_elem_value *ucontrol) | ||
505 | { | ||
506 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
507 | struct prodigy_hifi_spec *spec = ice->spec; | ||
508 | int ch, change = 0; | ||
509 | |||
510 | mutex_lock(&ice->gpio_mutex); | ||
511 | for (ch = 0; ch < 2; ch++) { | ||
512 | if (ucontrol->value.integer.value[ch] != spec->master[ch]) { | ||
513 | spec->master[ch] = ucontrol->value.integer.value[ch]; | ||
514 | |||
515 | /* Apply to front DAC */ | ||
516 | wm_set_vol(ice, WM_DAC_ATTEN_L + ch, | ||
517 | spec->vol[2 + ch], spec->master[ch]); | ||
518 | |||
519 | wm8766_set_vol(ice, WM8766_LDA1 + ch, | ||
520 | spec->vol[0 + ch], spec->master[ch]); | ||
521 | |||
522 | wm8766_set_vol(ice, WM8766_LDA2 + ch, | ||
523 | spec->vol[4 + ch], spec->master[ch]); | ||
524 | |||
525 | wm8766_set_vol(ice, WM8766_LDA3 + ch, | ||
526 | spec->vol[6 + ch], spec->master[ch]); | ||
527 | change = 1; | ||
528 | } | ||
529 | } | ||
530 | mutex_unlock(&ice->gpio_mutex); | ||
531 | return change; | ||
532 | } | ||
533 | |||
534 | |||
535 | /* KONSTI */ | ||
536 | |||
537 | static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
538 | struct snd_ctl_elem_info *uinfo) | ||
539 | { | ||
540 | static char* texts[32] = { | ||
541 | "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, | ||
542 | WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, | ||
543 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, | ||
544 | WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4, | ||
545 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4, | ||
546 | WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4, | ||
547 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | ||
548 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | ||
549 | WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5, | ||
550 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN5, | ||
551 | WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5, | ||
552 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | ||
553 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | ||
554 | WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5, | ||
555 | WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | ||
556 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | ||
557 | WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
558 | WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
559 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | ||
560 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5 | ||
561 | }; | ||
562 | |||
563 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
564 | uinfo->count = 1; | ||
565 | uinfo->value.enumerated.items = 32; | ||
566 | if (uinfo->value.enumerated.item > 31) | ||
567 | uinfo->value.enumerated.item = 31; | ||
568 | strcpy(uinfo->value.enumerated.name, | ||
569 | texts[uinfo->value.enumerated.item]); | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
574 | struct snd_ctl_elem_value *ucontrol) | ||
575 | { | ||
576 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
577 | |||
578 | mutex_lock(&ice->gpio_mutex); | ||
579 | ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; | ||
580 | mutex_unlock(&ice->gpio_mutex); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
585 | struct snd_ctl_elem_value *ucontrol) | ||
586 | { | ||
587 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
588 | unsigned short oval, nval; | ||
589 | int change = 0; | ||
590 | |||
591 | mutex_lock(&ice->gpio_mutex); | ||
592 | oval = wm_get(ice, WM_ADC_MUX); | ||
593 | nval = (oval & 0xe0) | ucontrol->value.integer.value[0]; | ||
594 | if (nval != oval) { | ||
595 | wm_put(ice, WM_ADC_MUX, nval); | ||
596 | change = 1; | ||
597 | } | ||
598 | mutex_unlock(&ice->gpio_mutex); | ||
599 | return change; | ||
600 | } | ||
601 | |||
602 | /* KONSTI */ | ||
603 | |||
604 | /* | ||
605 | * ADC gain mixer control (-64dB to 0dB) | ||
606 | */ | ||
607 | |||
608 | #define ADC_0dB 0xcf | ||
609 | #define ADC_RES 128 | ||
610 | #define ADC_MIN (ADC_0dB - ADC_RES) | ||
611 | |||
612 | static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, | ||
613 | struct snd_ctl_elem_info *uinfo) | ||
614 | { | ||
615 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
616 | uinfo->count = 2; | ||
617 | uinfo->value.integer.min = 0; /* mute (-64dB) */ | ||
618 | uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, | ||
623 | struct snd_ctl_elem_value *ucontrol) | ||
624 | { | ||
625 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
626 | unsigned short val; | ||
627 | int i; | ||
628 | |||
629 | mutex_lock(&ice->gpio_mutex); | ||
630 | for (i = 0; i < 2; i++) { | ||
631 | val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; | ||
632 | val = val > ADC_MIN ? (val - ADC_MIN) : 0; | ||
633 | ucontrol->value.integer.value[i] = val; | ||
634 | } | ||
635 | mutex_unlock(&ice->gpio_mutex); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, | ||
640 | struct snd_ctl_elem_value *ucontrol) | ||
641 | { | ||
642 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
643 | unsigned short ovol, nvol; | ||
644 | int i, idx, change = 0; | ||
645 | |||
646 | mutex_lock(&ice->gpio_mutex); | ||
647 | for (i = 0; i < 2; i++) { | ||
648 | nvol = ucontrol->value.integer.value[i]; | ||
649 | nvol = nvol ? (nvol + ADC_MIN) : 0; | ||
650 | idx = WM_ADC_ATTEN_L + i; | ||
651 | ovol = wm_get(ice, idx) & 0xff; | ||
652 | if (ovol != nvol) { | ||
653 | wm_put(ice, idx, nvol); | ||
654 | change = 1; | ||
655 | } | ||
656 | } | ||
657 | mutex_unlock(&ice->gpio_mutex); | ||
658 | return change; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * ADC input mux mixer control | ||
663 | */ | ||
664 | #define wm_adc_mux_info snd_ctl_boolean_mono_info | ||
665 | |||
666 | static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, | ||
667 | struct snd_ctl_elem_value *ucontrol) | ||
668 | { | ||
669 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
670 | int bit = kcontrol->private_value; | ||
671 | |||
672 | mutex_lock(&ice->gpio_mutex); | ||
673 | ucontrol->value.integer.value[0] = | ||
674 | (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; | ||
675 | mutex_unlock(&ice->gpio_mutex); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, | ||
680 | struct snd_ctl_elem_value *ucontrol) | ||
681 | { | ||
682 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
683 | int bit = kcontrol->private_value; | ||
684 | unsigned short oval, nval; | ||
685 | int change; | ||
686 | |||
687 | mutex_lock(&ice->gpio_mutex); | ||
688 | nval = oval = wm_get(ice, WM_ADC_MUX); | ||
689 | if (ucontrol->value.integer.value[0]) | ||
690 | nval |= (1 << bit); | ||
691 | else | ||
692 | nval &= ~(1 << bit); | ||
693 | change = nval != oval; | ||
694 | if (change) { | ||
695 | wm_put(ice, WM_ADC_MUX, nval); | ||
696 | } | ||
697 | mutex_unlock(&ice->gpio_mutex); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Analog bypass (In -> Out) | ||
703 | */ | ||
704 | #define wm_bypass_info snd_ctl_boolean_mono_info | ||
705 | |||
706 | static int wm_bypass_get(struct snd_kcontrol *kcontrol, | ||
707 | struct snd_ctl_elem_value *ucontrol) | ||
708 | { | ||
709 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
710 | |||
711 | mutex_lock(&ice->gpio_mutex); | ||
712 | ucontrol->value.integer.value[0] = | ||
713 | (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; | ||
714 | mutex_unlock(&ice->gpio_mutex); | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int wm_bypass_put(struct snd_kcontrol *kcontrol, | ||
719 | struct snd_ctl_elem_value *ucontrol) | ||
720 | { | ||
721 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
722 | unsigned short val, oval; | ||
723 | int change = 0; | ||
724 | |||
725 | mutex_lock(&ice->gpio_mutex); | ||
726 | val = oval = wm_get(ice, WM_OUT_MUX); | ||
727 | if (ucontrol->value.integer.value[0]) | ||
728 | val |= 0x04; | ||
729 | else | ||
730 | val &= ~0x04; | ||
731 | if (val != oval) { | ||
732 | wm_put(ice, WM_OUT_MUX, val); | ||
733 | change = 1; | ||
734 | } | ||
735 | mutex_unlock(&ice->gpio_mutex); | ||
736 | return change; | ||
737 | } | ||
738 | |||
739 | /* | ||
740 | * Left/Right swap | ||
741 | */ | ||
742 | #define wm_chswap_info snd_ctl_boolean_mono_info | ||
743 | |||
744 | static int wm_chswap_get(struct snd_kcontrol *kcontrol, | ||
745 | struct snd_ctl_elem_value *ucontrol) | ||
746 | { | ||
747 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
748 | |||
749 | mutex_lock(&ice->gpio_mutex); | ||
750 | ucontrol->value.integer.value[0] = | ||
751 | (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; | ||
752 | mutex_unlock(&ice->gpio_mutex); | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int wm_chswap_put(struct snd_kcontrol *kcontrol, | ||
757 | struct snd_ctl_elem_value *ucontrol) | ||
758 | { | ||
759 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
760 | unsigned short val, oval; | ||
761 | int change = 0; | ||
762 | |||
763 | mutex_lock(&ice->gpio_mutex); | ||
764 | oval = wm_get(ice, WM_DAC_CTRL1); | ||
765 | val = oval & 0x0f; | ||
766 | if (ucontrol->value.integer.value[0]) | ||
767 | val |= 0x60; | ||
768 | else | ||
769 | val |= 0x90; | ||
770 | if (val != oval) { | ||
771 | wm_put(ice, WM_DAC_CTRL1, val); | ||
772 | wm_put_nocache(ice, WM_DAC_CTRL1, val); | ||
773 | change = 1; | ||
774 | } | ||
775 | mutex_unlock(&ice->gpio_mutex); | ||
776 | return change; | ||
777 | } | ||
778 | |||
779 | |||
780 | /* | ||
781 | * mixers | ||
782 | */ | ||
783 | |||
784 | static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { | ||
785 | { | ||
786 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
787 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
788 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
789 | .name = "Master Playback Volume", | ||
790 | .info = wm_master_vol_info, | ||
791 | .get = wm_master_vol_get, | ||
792 | .put = wm_master_vol_put, | ||
793 | .tlv = { .p = db_scale_wm_dac } | ||
794 | }, | ||
795 | { | ||
796 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
797 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
798 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
799 | .name = "Front Playback Volume", | ||
800 | .info = wm_dac_vol_info, | ||
801 | .get = wm_dac_vol_get, | ||
802 | .put = wm_dac_vol_put, | ||
803 | .tlv = { .p = db_scale_wm_dac }, | ||
804 | }, | ||
805 | { | ||
806 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
807 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
808 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
809 | .name = "Rear Playback Volume", | ||
810 | .info = wm8766_vol_info, | ||
811 | .get = wm8766_vol_get, | ||
812 | .put = wm8766_vol_put, | ||
813 | .private_value = (2 << 8) | 0, | ||
814 | .tlv = { .p = db_scale_wm_dac }, | ||
815 | }, | ||
816 | { | ||
817 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
818 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
819 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
820 | .name = "Center Playback Volume", | ||
821 | .info = wm8766_vol_info, | ||
822 | .get = wm8766_vol_get, | ||
823 | .put = wm8766_vol_put, | ||
824 | .private_value = (1 << 8) | 4, | ||
825 | .tlv = { .p = db_scale_wm_dac } | ||
826 | }, | ||
827 | { | ||
828 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
829 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
830 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
831 | .name = "LFE Playback Volume", | ||
832 | .info = wm8766_vol_info, | ||
833 | .get = wm8766_vol_get, | ||
834 | .put = wm8766_vol_put, | ||
835 | .private_value = (1 << 8) | 5, | ||
836 | .tlv = { .p = db_scale_wm_dac } | ||
837 | }, | ||
838 | { | ||
839 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
840 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
841 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
842 | .name = "Side Playback Volume", | ||
843 | .info = wm8766_vol_info, | ||
844 | .get = wm8766_vol_get, | ||
845 | .put = wm8766_vol_put, | ||
846 | .private_value = (2 << 8) | 6, | ||
847 | .tlv = { .p = db_scale_wm_dac }, | ||
848 | }, | ||
849 | { | ||
850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
851 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
852 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | ||
853 | .name = "Capture Volume", | ||
854 | .info = wm_adc_vol_info, | ||
855 | .get = wm_adc_vol_get, | ||
856 | .put = wm_adc_vol_put, | ||
857 | .tlv = { .p = db_scale_wm_dac }, | ||
858 | }, | ||
859 | { | ||
860 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
861 | .name = "CD Capture Switch", | ||
862 | .info = wm_adc_mux_info, | ||
863 | .get = wm_adc_mux_get, | ||
864 | .put = wm_adc_mux_put, | ||
865 | .private_value = 0, | ||
866 | }, | ||
867 | { | ||
868 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
869 | .name = "Line Capture Switch", | ||
870 | .info = wm_adc_mux_info, | ||
871 | .get = wm_adc_mux_get, | ||
872 | .put = wm_adc_mux_put, | ||
873 | .private_value = 1, | ||
874 | }, | ||
875 | { | ||
876 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
877 | .name = "Analog Bypass Switch", | ||
878 | .info = wm_bypass_info, | ||
879 | .get = wm_bypass_get, | ||
880 | .put = wm_bypass_put, | ||
881 | }, | ||
882 | { | ||
883 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
884 | .name = "Swap Output Channels", | ||
885 | .info = wm_chswap_info, | ||
886 | .get = wm_chswap_get, | ||
887 | .put = wm_chswap_put, | ||
888 | }, | ||
889 | { | ||
890 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
891 | .name = "Analog Capture Source", | ||
892 | .info = wm_adc_mux_enum_info, | ||
893 | .get = wm_adc_mux_enum_get, | ||
894 | .put = wm_adc_mux_enum_put, | ||
895 | }, | ||
896 | }; | ||
897 | |||
898 | /* | ||
899 | * WM codec registers | ||
900 | */ | ||
901 | static void wm_proc_regs_write(struct snd_info_entry *entry, | ||
902 | struct snd_info_buffer *buffer) | ||
903 | { | ||
904 | struct snd_ice1712 *ice = entry->private_data; | ||
905 | char line[64]; | ||
906 | unsigned int reg, val; | ||
907 | mutex_lock(&ice->gpio_mutex); | ||
908 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
909 | if (sscanf(line, "%x %x", ®, &val) != 2) | ||
910 | continue; | ||
911 | if (reg <= 0x17 && val <= 0xffff) | ||
912 | wm_put(ice, reg, val); | ||
913 | } | ||
914 | mutex_unlock(&ice->gpio_mutex); | ||
915 | } | ||
916 | |||
917 | static void wm_proc_regs_read(struct snd_info_entry *entry, | ||
918 | struct snd_info_buffer *buffer) | ||
919 | { | ||
920 | struct snd_ice1712 *ice = entry->private_data; | ||
921 | int reg, val; | ||
922 | |||
923 | mutex_lock(&ice->gpio_mutex); | ||
924 | for (reg = 0; reg <= 0x17; reg++) { | ||
925 | val = wm_get(ice, reg); | ||
926 | snd_iprintf(buffer, "%02x = %04x\n", reg, val); | ||
927 | } | ||
928 | mutex_unlock(&ice->gpio_mutex); | ||
929 | } | ||
930 | |||
931 | static void wm_proc_init(struct snd_ice1712 *ice) | ||
932 | { | ||
933 | struct snd_info_entry *entry; | ||
934 | if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { | ||
935 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); | ||
936 | entry->mode |= S_IWUSR; | ||
937 | entry->c.text.write = wm_proc_regs_write; | ||
938 | } | ||
939 | } | ||
940 | |||
941 | static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) | ||
942 | { | ||
943 | unsigned int i; | ||
944 | int err; | ||
945 | |||
946 | for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) { | ||
947 | err = snd_ctl_add(ice->card, | ||
948 | snd_ctl_new1(&prodigy_hifi_controls[i], ice)); | ||
949 | if (err < 0) | ||
950 | return err; | ||
951 | } | ||
952 | |||
953 | wm_proc_init(ice); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) | ||
959 | { | ||
960 | unsigned int i; | ||
961 | int err; | ||
962 | |||
963 | for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) { | ||
964 | err = snd_ctl_add(ice->card, | ||
965 | snd_ctl_new1(&prodigy_hd2_controls[i], ice)); | ||
966 | if (err < 0) | ||
967 | return err; | ||
968 | } | ||
969 | |||
970 | wm_proc_init(ice); | ||
971 | |||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | |||
976 | /* | ||
977 | * initialize the chip | ||
978 | */ | ||
979 | static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) | ||
980 | { | ||
981 | static unsigned short wm_inits[] = { | ||
982 | /* These come first to reduce init pop noise */ | ||
983 | WM_ADC_MUX, 0x0003, /* ADC mute */ | ||
984 | /* 0x00c0 replaced by 0x0003 */ | ||
985 | |||
986 | WM_DAC_MUTE, 0x0001, /* DAC softmute */ | ||
987 | WM_DAC_CTRL1, 0x0000, /* DAC mute */ | ||
988 | |||
989 | WM_POWERDOWN, 0x0008, /* All power-up except HP */ | ||
990 | WM_RESET, 0x0000, /* reset */ | ||
991 | }; | ||
992 | static unsigned short wm_inits2[] = { | ||
993 | WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ | ||
994 | WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | ||
995 | WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | ||
996 | WM_DAC_CTRL1, 0x0090, /* DAC L/R */ | ||
997 | WM_OUT_MUX, 0x0001, /* OUT DAC */ | ||
998 | WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ | ||
999 | WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ | ||
1000 | WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ | ||
1001 | WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ | ||
1002 | WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ | ||
1003 | WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ | ||
1004 | WM_PHASE_SWAP, 0x0000, /* phase normal */ | ||
1005 | #if 0 | ||
1006 | WM_DAC_MASTER, 0x0100, /* DAC master muted */ | ||
1007 | #endif | ||
1008 | WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ | ||
1009 | WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ | ||
1010 | WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ | ||
1011 | #if 1 | ||
1012 | WM_ALC_CTRL1, 0x007b, /* */ | ||
1013 | WM_ALC_CTRL2, 0x0000, /* */ | ||
1014 | WM_ALC_CTRL3, 0x0000, /* */ | ||
1015 | WM_NOISE_GATE, 0x0000, /* */ | ||
1016 | #endif | ||
1017 | WM_DAC_MUTE, 0x0000, /* DAC unmute */ | ||
1018 | WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ | ||
1019 | }; | ||
1020 | static unsigned short wm8766_inits[] = { | ||
1021 | WM8766_RESET, 0x0000, | ||
1022 | WM8766_DAC_CTRL, 0x0120, | ||
1023 | WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ | ||
1024 | WM8766_DAC_CTRL2, 0x0001, | ||
1025 | WM8766_DAC_CTRL3, 0x0080, | ||
1026 | WM8766_LDA1, 0x0100, | ||
1027 | WM8766_LDA2, 0x0100, | ||
1028 | WM8766_LDA3, 0x0100, | ||
1029 | WM8766_RDA1, 0x0100, | ||
1030 | WM8766_RDA2, 0x0100, | ||
1031 | WM8766_RDA3, 0x0100, | ||
1032 | WM8766_MUTE1, 0x0000, | ||
1033 | WM8766_MUTE2, 0x0000, | ||
1034 | }; | ||
1035 | |||
1036 | struct prodigy_hifi_spec *spec; | ||
1037 | unsigned int i; | ||
1038 | |||
1039 | ice->vt1720 = 0; | ||
1040 | ice->vt1724 = 1; | ||
1041 | |||
1042 | ice->num_total_dacs = 8; | ||
1043 | ice->num_total_adcs = 1; | ||
1044 | |||
1045 | /* HACK - use this as the SPDIF source. | ||
1046 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | ||
1047 | */ | ||
1048 | ice->gpio.saved[0] = 0; | ||
1049 | /* to remeber the register values */ | ||
1050 | |||
1051 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
1052 | if (! ice->akm) | ||
1053 | return -ENOMEM; | ||
1054 | ice->akm_codecs = 1; | ||
1055 | |||
1056 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1057 | if (!spec) | ||
1058 | return -ENOMEM; | ||
1059 | ice->spec = spec; | ||
1060 | |||
1061 | /* initialize WM8776 codec */ | ||
1062 | for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) | ||
1063 | wm_put(ice, wm_inits[i], wm_inits[i+1]); | ||
1064 | schedule_timeout_uninterruptible(1); | ||
1065 | for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) | ||
1066 | wm_put(ice, wm_inits2[i], wm_inits2[i+1]); | ||
1067 | |||
1068 | /* initialize WM8766 codec */ | ||
1069 | for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) | ||
1070 | wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]); | ||
1071 | |||
1072 | |||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /* | ||
1078 | * initialize the chip | ||
1079 | */ | ||
1080 | static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) | ||
1081 | { | ||
1082 | static unsigned short ak4396_inits[] = { | ||
1083 | AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ | ||
1084 | AK4396_CTRL2, 0x02, | ||
1085 | AK4396_CTRL3, 0x00, | ||
1086 | AK4396_LCH_ATT, 0x00, | ||
1087 | AK4396_RCH_ATT, 0x00, | ||
1088 | }; | ||
1089 | |||
1090 | struct prodigy_hifi_spec *spec; | ||
1091 | unsigned int i; | ||
1092 | |||
1093 | ice->vt1720 = 0; | ||
1094 | ice->vt1724 = 1; | ||
1095 | |||
1096 | ice->num_total_dacs = 1; | ||
1097 | ice->num_total_adcs = 1; | ||
1098 | |||
1099 | /* HACK - use this as the SPDIF source. | ||
1100 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | ||
1101 | */ | ||
1102 | ice->gpio.saved[0] = 0; | ||
1103 | /* to remeber the register values */ | ||
1104 | |||
1105 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
1106 | if (! ice->akm) | ||
1107 | return -ENOMEM; | ||
1108 | ice->akm_codecs = 1; | ||
1109 | |||
1110 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1111 | if (!spec) | ||
1112 | return -ENOMEM; | ||
1113 | ice->spec = spec; | ||
1114 | |||
1115 | /* initialize ak4396 codec */ | ||
1116 | /* reset codec */ | ||
1117 | ak4396_write(ice, AK4396_CTRL1, 0x86); | ||
1118 | msleep(100); | ||
1119 | ak4396_write(ice, AK4396_CTRL1, 0x87); | ||
1120 | |||
1121 | for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) | ||
1122 | ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); | ||
1123 | |||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
1127 | |||
1128 | static unsigned char prodigy71hifi_eeprom[] __devinitdata = { | ||
1129 | 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | ||
1130 | 0x80, /* ACLINK: I2S */ | ||
1131 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1132 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
1133 | 0xff, /* GPIO_DIR */ | ||
1134 | 0xff, /* GPIO_DIR1 */ | ||
1135 | 0x5f, /* GPIO_DIR2 */ | ||
1136 | 0x00, /* GPIO_MASK */ | ||
1137 | 0x00, /* GPIO_MASK1 */ | ||
1138 | 0x00, /* GPIO_MASK2 */ | ||
1139 | 0x00, /* GPIO_STATE */ | ||
1140 | 0x00, /* GPIO_STATE1 */ | ||
1141 | 0x00, /* GPIO_STATE2 */ | ||
1142 | }; | ||
1143 | |||
1144 | static unsigned char prodigyhd2_eeprom[] __devinitdata = { | ||
1145 | 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ | ||
1146 | 0x80, /* ACLINK: I2S */ | ||
1147 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1148 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ | ||
1149 | 0xff, /* GPIO_DIR */ | ||
1150 | 0xff, /* GPIO_DIR1 */ | ||
1151 | 0x5f, /* GPIO_DIR2 */ | ||
1152 | 0x00, /* GPIO_MASK */ | ||
1153 | 0x00, /* GPIO_MASK1 */ | ||
1154 | 0x00, /* GPIO_MASK2 */ | ||
1155 | 0x00, /* GPIO_STATE */ | ||
1156 | 0x00, /* GPIO_STATE1 */ | ||
1157 | 0x00, /* GPIO_STATE2 */ | ||
1158 | }; | ||
1159 | |||
1160 | static unsigned char fortissimo4_eeprom[] __devinitdata = { | ||
1161 | 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ | ||
1162 | 0x80, /* ACLINK: I2S */ | ||
1163 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | ||
1164 | 0xc1, /* SPDIF: out-en, out-int */ | ||
1165 | 0xff, /* GPIO_DIR */ | ||
1166 | 0xff, /* GPIO_DIR1 */ | ||
1167 | 0x5f, /* GPIO_DIR2 */ | ||
1168 | 0x00, /* GPIO_MASK */ | ||
1169 | 0x00, /* GPIO_MASK1 */ | ||
1170 | 0x00, /* GPIO_MASK2 */ | ||
1171 | 0x00, /* GPIO_STATE */ | ||
1172 | 0x00, /* GPIO_STATE1 */ | ||
1173 | 0x00, /* GPIO_STATE2 */ | ||
1174 | }; | ||
1175 | |||
1176 | /* entry point */ | ||
1177 | struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { | ||
1178 | { | ||
1179 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, | ||
1180 | .name = "Audiotrak Prodigy 7.1 HiFi", | ||
1181 | .model = "prodigy71hifi", | ||
1182 | .chip_init = prodigy_hifi_init, | ||
1183 | .build_controls = prodigy_hifi_add_controls, | ||
1184 | .eeprom_size = sizeof(prodigy71hifi_eeprom), | ||
1185 | .eeprom_data = prodigy71hifi_eeprom, | ||
1186 | .driver = "Prodigy71HIFI", | ||
1187 | }, | ||
1188 | { | ||
1189 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2, | ||
1190 | .name = "Audiotrak Prodigy HD2", | ||
1191 | .model = "prodigyhd2", | ||
1192 | .chip_init = prodigy_hd2_init, | ||
1193 | .build_controls = prodigy_hd2_add_controls, | ||
1194 | .eeprom_size = sizeof(prodigyhd2_eeprom), | ||
1195 | .eeprom_data = prodigyhd2_eeprom, | ||
1196 | .driver = "Prodigy71HD2", | ||
1197 | }, | ||
1198 | { | ||
1199 | .subvendor = VT1724_SUBDEVICE_FORTISSIMO4, | ||
1200 | .name = "Hercules Fortissimo IV", | ||
1201 | .model = "fortissimo4", | ||
1202 | .chip_init = prodigy_hifi_init, | ||
1203 | .build_controls = prodigy_hifi_add_controls, | ||
1204 | .eeprom_size = sizeof(fortissimo4_eeprom), | ||
1205 | .eeprom_data = fortissimo4_eeprom, | ||
1206 | .driver = "Fortissimo4", | ||
1207 | }, | ||
1208 | { } /* terminator */ | ||
1209 | }; | ||
1210 | |||
diff --git a/sound/pci/ice1712/prodigy_hifi.h b/sound/pci/ice1712/prodigy_hifi.h new file mode 100644 index 000000000000..a4415d455d9e --- /dev/null +++ b/sound/pci/ice1712/prodigy_hifi.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef __SOUND_PRODIGY_HIFI_H | ||
2 | #define __SOUND_PRODIGY_HIFI_H | ||
3 | |||
4 | /* | ||
5 | * ALSA driver for VIA VT1724 (Envy24HT) | ||
6 | * | ||
7 | * Lowlevel functions for Audiotrak Prodigy Hifi | ||
8 | * | ||
9 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #define PRODIGY_HIFI_DEVICE_DESC "{Audiotrak,Prodigy 7.1 HIFI},"\ | ||
28 | "{Audiotrak Prodigy HD2},"\ | ||
29 | "{Hercules Fortissimo IV}," | ||
30 | |||
31 | #define VT1724_SUBDEVICE_PRODIGY_HIFI 0x38315441 /* PRODIGY 7.1 HIFI */ | ||
32 | #define VT1724_SUBDEVICE_PRODIGY_HD2 0x37315441 /* PRODIGY HD2 */ | ||
33 | #define VT1724_SUBDEVICE_FORTISSIMO4 0x81160100 /* Fortissimo IV */ | ||
34 | |||
35 | |||
36 | extern struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[]; | ||
37 | |||
38 | #endif /* __SOUND_PRODIGY_HIFI_H */ | ||
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index d18a31e188a9..ddd5fc8d4fe1 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -33,6 +32,12 @@ | |||
33 | #include "envy24ht.h" | 32 | #include "envy24ht.h" |
34 | #include "revo.h" | 33 | #include "revo.h" |
35 | 34 | ||
35 | /* a non-standard I2C device for revo51 */ | ||
36 | struct revo51_spec { | ||
37 | struct snd_i2c_device *dev; | ||
38 | struct snd_pt2258 *pt2258; | ||
39 | } revo51; | ||
40 | |||
36 | static void revo_i2s_mclk_changed(struct snd_ice1712 *ice) | 41 | static void revo_i2s_mclk_changed(struct snd_ice1712 *ice) |
37 | { | 42 | { |
38 | /* assert PRST# to converters; MT05 bit 7 */ | 43 | /* assert PRST# to converters; MT05 bit 7 */ |
@@ -153,8 +158,14 @@ static struct snd_i2c_bit_ops revo51_bit_ops = { | |||
153 | static int revo51_i2c_init(struct snd_ice1712 *ice, | 158 | static int revo51_i2c_init(struct snd_ice1712 *ice, |
154 | struct snd_pt2258 *pt) | 159 | struct snd_pt2258 *pt) |
155 | { | 160 | { |
161 | struct revo51_spec *spec; | ||
156 | int err; | 162 | int err; |
157 | 163 | ||
164 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
165 | if (!spec) | ||
166 | return -ENOMEM; | ||
167 | ice->spec = spec; | ||
168 | |||
158 | /* create the I2C bus */ | 169 | /* create the I2C bus */ |
159 | err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); | 170 | err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c); |
160 | if (err < 0) | 171 | if (err < 0) |
@@ -164,15 +175,14 @@ static int revo51_i2c_init(struct snd_ice1712 *ice, | |||
164 | ice->i2c->hw_ops.bit = &revo51_bit_ops; | 175 | ice->i2c->hw_ops.bit = &revo51_bit_ops; |
165 | 176 | ||
166 | /* create the I2C device */ | 177 | /* create the I2C device */ |
167 | err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, | 178 | err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, &spec->dev); |
168 | &ice->spec.revo51.dev); | ||
169 | if (err < 0) | 179 | if (err < 0) |
170 | return err; | 180 | return err; |
171 | 181 | ||
172 | pt->card = ice->card; | 182 | pt->card = ice->card; |
173 | pt->i2c_bus = ice->i2c; | 183 | pt->i2c_bus = ice->i2c; |
174 | pt->i2c_dev = ice->spec.revo51.dev; | 184 | pt->i2c_dev = spec->dev; |
175 | ice->spec.revo51.pt2258 = pt; | 185 | spec->pt2258 = pt; |
176 | 186 | ||
177 | snd_pt2258_reset(pt); | 187 | snd_pt2258_reset(pt); |
178 | 188 | ||
@@ -556,6 +566,7 @@ static int __devinit revo_init(struct snd_ice1712 *ice) | |||
556 | 566 | ||
557 | static int __devinit revo_add_controls(struct snd_ice1712 *ice) | 567 | static int __devinit revo_add_controls(struct snd_ice1712 *ice) |
558 | { | 568 | { |
569 | struct revo51_spec *spec; | ||
559 | int err; | 570 | int err; |
560 | 571 | ||
561 | switch (ice->eeprom.subvendor) { | 572 | switch (ice->eeprom.subvendor) { |
@@ -568,7 +579,8 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) | |||
568 | err = snd_ice1712_akm4xxx_build_controls(ice); | 579 | err = snd_ice1712_akm4xxx_build_controls(ice); |
569 | if (err < 0) | 580 | if (err < 0) |
570 | return err; | 581 | return err; |
571 | err = snd_pt2258_build_controls(ice->spec.revo51.pt2258); | 582 | spec = ice->spec; |
583 | err = snd_pt2258_build_controls(spec->pt2258); | ||
572 | if (err < 0) | 584 | if (err < 0) |
573 | return err; | 585 | return err; |
574 | break; | 586 | break; |
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c new file mode 100644 index 000000000000..69673b95869d --- /dev/null +++ b/sound/pci/ice1712/se.c | |||
@@ -0,0 +1,774 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI | ||
5 | * | ||
6 | * Copyright (c) 2007 Shin-ya Okada sh_okada(at)d4.dion.ne.jp | ||
7 | * (at) -> @ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <asm/io.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/tlv.h> | ||
32 | |||
33 | #include "ice1712.h" | ||
34 | #include "envy24ht.h" | ||
35 | #include "se.h" | ||
36 | |||
37 | struct se_spec { | ||
38 | struct { | ||
39 | unsigned char ch1, ch2; | ||
40 | } vol[8]; | ||
41 | }; | ||
42 | |||
43 | /****************************************************************************/ | ||
44 | /* ONKYO WAVIO SE-200PCI */ | ||
45 | /****************************************************************************/ | ||
46 | /* | ||
47 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
48 | * XIN1 49.152MHz | ||
49 | * not have UART | ||
50 | * one stereo ADC and a S/PDIF receiver connected | ||
51 | * four stereo DACs connected | ||
52 | * | ||
53 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
54 | * use I2C, not use AC97 | ||
55 | * | ||
56 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
57 | * I2S codec has no volume/mute control feature | ||
58 | * I2S codec supports 96KHz and 192KHz | ||
59 | * I2S codec 24bits | ||
60 | * | ||
61 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
62 | * Enable integrated S/PDIF transmitter | ||
63 | * internal S/PDIF out implemented | ||
64 | * S/PDIF is stereo | ||
65 | * External S/PDIF out implemented | ||
66 | * | ||
67 | * | ||
68 | * ** connected chips ** | ||
69 | * | ||
70 | * WM8740 | ||
71 | * A 2ch-DAC of main outputs. | ||
72 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
73 | * The sample-rate are automatically changed. | ||
74 | * ML/I2S (28pin) --------+ | ||
75 | * MC/DM1 (27pin) -- 5V | | ||
76 | * MD/DM0 (26pin) -- GND | | ||
77 | * MUTEB (25pin) -- NC | | ||
78 | * MODE (24pin) -- GND | | ||
79 | * CSBIW (23pin) --------+ | ||
80 | * | | ||
81 | * RSTB (22pin) --R(1K)-+ | ||
82 | * Probably it reduce the noise from the control line. | ||
83 | * | ||
84 | * WM8766 | ||
85 | * A 6ch-DAC for surrounds. | ||
86 | * It's control wire was connected to GPIOxx (3-wire serial interface) | ||
87 | * ML/I2S (11pin) -- GPIO18 | ||
88 | * MC/IWL (12pin) -- GPIO17 | ||
89 | * MD/DM (13pin) -- GPIO16 | ||
90 | * MUTE (14pin) -- GPIO01 | ||
91 | * | ||
92 | * WM8776 | ||
93 | * A 2ch-ADC(with 10ch-selector) plus 2ch-DAC. | ||
94 | * It's control wire was connected to SDA/SCLK (2-wire serial interface) | ||
95 | * MODE (16pin) -- R(1K) -- GND | ||
96 | * CE (17pin) -- R(1K) -- GND 2-wire mode (address=0x34) | ||
97 | * DI (18pin) -- SDA | ||
98 | * CL (19pin) -- SCLK | ||
99 | * | ||
100 | * | ||
101 | * ** output pins and device names ** | ||
102 | * | ||
103 | * 7.1ch name -- output connector color -- device (-D option) | ||
104 | * | ||
105 | * FRONT 2ch -- green -- plughw:0,0 | ||
106 | * CENTER(Lch) SUBWOOFER(Rch) -- black -- plughw:0,2,0 | ||
107 | * SURROUND 2ch -- orange -- plughw:0,2,1 | ||
108 | * SURROUND BACK 2ch -- white -- plughw:0,2,2 | ||
109 | * | ||
110 | */ | ||
111 | |||
112 | |||
113 | /****************************************************************************/ | ||
114 | /* WM8740 interface */ | ||
115 | /****************************************************************************/ | ||
116 | |||
117 | static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) | ||
118 | { | ||
119 | /* nothing to do */ | ||
120 | } | ||
121 | |||
122 | |||
123 | static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice, | ||
124 | unsigned int rate) | ||
125 | { | ||
126 | /* nothing to do */ | ||
127 | } | ||
128 | |||
129 | |||
130 | /****************************************************************************/ | ||
131 | /* WM8766 interface */ | ||
132 | /****************************************************************************/ | ||
133 | |||
134 | static void se200pci_WM8766_write(struct snd_ice1712 *ice, | ||
135 | unsigned int addr, unsigned int data) | ||
136 | { | ||
137 | unsigned int st; | ||
138 | unsigned int bits; | ||
139 | int i; | ||
140 | const unsigned int DATA = 0x010000; | ||
141 | const unsigned int CLOCK = 0x020000; | ||
142 | const unsigned int LOAD = 0x040000; | ||
143 | const unsigned int ALL_MASK = (DATA | CLOCK | LOAD); | ||
144 | |||
145 | snd_ice1712_save_gpio_status(ice); | ||
146 | |||
147 | st = ((addr & 0x7f) << 9) | (data & 0x1ff); | ||
148 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK); | ||
149 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK); | ||
150 | bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK; | ||
151 | |||
152 | snd_ice1712_gpio_write(ice, bits); | ||
153 | for (i = 0; i < 16; i++) { | ||
154 | udelay(1); | ||
155 | bits &= ~CLOCK; | ||
156 | st = (st << 1); | ||
157 | if (st & 0x10000) | ||
158 | bits |= DATA; | ||
159 | else | ||
160 | bits &= ~DATA; | ||
161 | |||
162 | snd_ice1712_gpio_write(ice, bits); | ||
163 | |||
164 | udelay(1); | ||
165 | bits |= CLOCK; | ||
166 | snd_ice1712_gpio_write(ice, bits); | ||
167 | } | ||
168 | |||
169 | udelay(1); | ||
170 | bits |= LOAD; | ||
171 | snd_ice1712_gpio_write(ice, bits); | ||
172 | |||
173 | udelay(1); | ||
174 | bits |= (DATA | CLOCK); | ||
175 | snd_ice1712_gpio_write(ice, bits); | ||
176 | |||
177 | snd_ice1712_restore_gpio_status(ice); | ||
178 | } | ||
179 | |||
180 | static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, | ||
181 | unsigned int vol1, unsigned int vol2) | ||
182 | { | ||
183 | switch (ch) { | ||
184 | case 0: | ||
185 | se200pci_WM8766_write(ice, 0x000, vol1); | ||
186 | se200pci_WM8766_write(ice, 0x001, vol2 | 0x100); | ||
187 | break; | ||
188 | case 1: | ||
189 | se200pci_WM8766_write(ice, 0x004, vol1); | ||
190 | se200pci_WM8766_write(ice, 0x005, vol2 | 0x100); | ||
191 | break; | ||
192 | case 2: | ||
193 | se200pci_WM8766_write(ice, 0x006, vol1); | ||
194 | se200pci_WM8766_write(ice, 0x007, vol2 | 0x100); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) | ||
200 | { | ||
201 | se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ | ||
202 | udelay(10); | ||
203 | |||
204 | se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */ | ||
205 | se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */ | ||
206 | se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */ | ||
207 | |||
208 | se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */ | ||
209 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
210 | se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */ | ||
211 | se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */ | ||
212 | se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */ | ||
213 | |||
214 | se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */ | ||
215 | se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */ | ||
216 | } | ||
217 | |||
218 | static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice, | ||
219 | unsigned int rate) | ||
220 | { | ||
221 | if (rate > 96000) | ||
222 | se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */ | ||
223 | else | ||
224 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
225 | } | ||
226 | |||
227 | |||
228 | /****************************************************************************/ | ||
229 | /* WM8776 interface */ | ||
230 | /****************************************************************************/ | ||
231 | |||
232 | static void se200pci_WM8776_write(struct snd_ice1712 *ice, | ||
233 | unsigned int addr, unsigned int data) | ||
234 | { | ||
235 | unsigned int val; | ||
236 | |||
237 | val = (addr << 9) | data; | ||
238 | snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff); | ||
239 | } | ||
240 | |||
241 | |||
242 | static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice, | ||
243 | unsigned int vol1, unsigned int vol2) | ||
244 | { | ||
245 | se200pci_WM8776_write(ice, 0x03, vol1); | ||
246 | se200pci_WM8776_write(ice, 0x04, vol2 | 0x100); | ||
247 | } | ||
248 | |||
249 | static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, | ||
250 | unsigned int vol1, unsigned int vol2) | ||
251 | { | ||
252 | se200pci_WM8776_write(ice, 0x0e, vol1); | ||
253 | se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); | ||
254 | } | ||
255 | |||
256 | static const char *se200pci_sel[] = { | ||
257 | "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL | ||
258 | }; | ||
259 | |||
260 | static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice, | ||
261 | unsigned int sel) | ||
262 | { | ||
263 | static unsigned char vals[] = { | ||
264 | /* LINE, CD, MIC, ALL, GND */ | ||
265 | 0x10, 0x04, 0x08, 0x1c, 0x03 | ||
266 | }; | ||
267 | if (sel > 4) | ||
268 | sel = 4; | ||
269 | se200pci_WM8776_write(ice, 0x15, vals[sel]); | ||
270 | } | ||
271 | |||
272 | static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) | ||
273 | { | ||
274 | /* AFL -- After Fader Listening */ | ||
275 | if (afl) | ||
276 | se200pci_WM8776_write(ice, 0x16, 0x005); | ||
277 | else | ||
278 | se200pci_WM8776_write(ice, 0x16, 0x001); | ||
279 | } | ||
280 | |||
281 | static const char *se200pci_agc[] = { | ||
282 | "Off", "LimiterMode", "ALCMode", NULL | ||
283 | }; | ||
284 | |||
285 | static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) | ||
286 | { | ||
287 | /* AGC -- Auto Gain Control of the input */ | ||
288 | switch (agc) { | ||
289 | case 0: | ||
290 | se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */ | ||
291 | break; | ||
292 | case 1: | ||
293 | se200pci_WM8776_write(ice, 0x10, 0x07b); | ||
294 | se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */ | ||
295 | break; | ||
296 | case 2: | ||
297 | se200pci_WM8776_write(ice, 0x10, 0x1fb); | ||
298 | se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */ | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) | ||
304 | { | ||
305 | int i; | ||
306 | static unsigned short __devinitdata default_values[] = { | ||
307 | 0x100, 0x100, 0x100, | ||
308 | 0x100, 0x100, 0x100, | ||
309 | 0x000, 0x090, 0x000, 0x000, | ||
310 | 0x022, 0x022, 0x022, | ||
311 | 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, | ||
312 | 0x032, 0x000, 0x0a6, 0x001, 0x001 | ||
313 | }; | ||
314 | |||
315 | se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */ | ||
316 | /* ADC and DAC interface is I2S 24bits mode */ | ||
317 | /* The sample-rate are automatically changed */ | ||
318 | udelay(10); | ||
319 | /* BUT my board can not do reset all, so I load all by manually. */ | ||
320 | for (i = 0; i < ARRAY_SIZE(default_values); i++) | ||
321 | se200pci_WM8776_write(ice, i, default_values[i]); | ||
322 | |||
323 | se200pci_WM8776_set_input_selector(ice, 0); | ||
324 | se200pci_WM8776_set_afl(ice, 0); | ||
325 | se200pci_WM8776_set_agc(ice, 0); | ||
326 | se200pci_WM8776_set_input_volume(ice, 0, 0); | ||
327 | se200pci_WM8776_set_output_volume(ice, 0, 0); | ||
328 | |||
329 | /* head phone mute and power down */ | ||
330 | se200pci_WM8776_write(ice, 0x00, 0); | ||
331 | se200pci_WM8776_write(ice, 0x01, 0); | ||
332 | se200pci_WM8776_write(ice, 0x02, 0x100); | ||
333 | se200pci_WM8776_write(ice, 0x0d, 0x080); | ||
334 | } | ||
335 | |||
336 | static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice, | ||
337 | unsigned int rate) | ||
338 | { | ||
339 | /* nothing to do */ | ||
340 | } | ||
341 | |||
342 | |||
343 | /****************************************************************************/ | ||
344 | /* runtime interface */ | ||
345 | /****************************************************************************/ | ||
346 | |||
347 | static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
348 | { | ||
349 | se200pci_WM8740_set_pro_rate(ice, rate); | ||
350 | se200pci_WM8766_set_pro_rate(ice, rate); | ||
351 | se200pci_WM8776_set_pro_rate(ice, rate); | ||
352 | } | ||
353 | |||
354 | struct se200pci_control { | ||
355 | char *name; | ||
356 | enum { | ||
357 | WM8766, | ||
358 | WM8776in, | ||
359 | WM8776out, | ||
360 | WM8776sel, | ||
361 | WM8776agc, | ||
362 | WM8776afl | ||
363 | } target; | ||
364 | enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; | ||
365 | int ch; | ||
366 | const char **member; | ||
367 | const char *comment; | ||
368 | }; | ||
369 | |||
370 | static const struct se200pci_control se200pci_cont[] = { | ||
371 | { | ||
372 | .name = "Front Playback Volume", | ||
373 | .target = WM8776out, | ||
374 | .type = VOLUME1, | ||
375 | .comment = "Front(green)" | ||
376 | }, | ||
377 | { | ||
378 | .name = "Side Playback Volume", | ||
379 | .target = WM8766, | ||
380 | .type = VOLUME1, | ||
381 | .ch = 1, | ||
382 | .comment = "Surround(orange)" | ||
383 | }, | ||
384 | { | ||
385 | .name = "Surround Playback Volume", | ||
386 | .target = WM8766, | ||
387 | .type = VOLUME1, | ||
388 | .ch = 2, | ||
389 | .comment = "SurroundBack(white)" | ||
390 | }, | ||
391 | { | ||
392 | .name = "CLFE Playback Volume", | ||
393 | .target = WM8766, | ||
394 | .type = VOLUME1, | ||
395 | .ch = 0, | ||
396 | .comment = "Center(Lch)&SubWoofer(Rch)(black)" | ||
397 | }, | ||
398 | { | ||
399 | .name = "Capture Volume", | ||
400 | .target = WM8776in, | ||
401 | .type = VOLUME2 | ||
402 | }, | ||
403 | { | ||
404 | .name = "Capture Select", | ||
405 | .target = WM8776sel, | ||
406 | .type = ENUM, | ||
407 | .member = se200pci_sel | ||
408 | }, | ||
409 | { | ||
410 | .name = "AGC Capture Mode", | ||
411 | .target = WM8776agc, | ||
412 | .type = ENUM, | ||
413 | .member = se200pci_agc | ||
414 | }, | ||
415 | { | ||
416 | .name = "AFL Bypass Playback Switch", | ||
417 | .target = WM8776afl, | ||
418 | .type = BOOLEAN | ||
419 | } | ||
420 | }; | ||
421 | |||
422 | static int se200pci_get_enum_count(int n) | ||
423 | { | ||
424 | const char **member; | ||
425 | int c; | ||
426 | |||
427 | member = se200pci_cont[n].member; | ||
428 | if (!member) | ||
429 | return 0; | ||
430 | for (c = 0; member[c]; c++) | ||
431 | ; | ||
432 | return c; | ||
433 | } | ||
434 | |||
435 | static int se200pci_cont_volume_info(struct snd_kcontrol *kc, | ||
436 | struct snd_ctl_elem_info *uinfo) | ||
437 | { | ||
438 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
439 | uinfo->count = 2; | ||
440 | uinfo->value.integer.min = 0; /* mute */ | ||
441 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | #define se200pci_cont_boolean_info snd_ctl_boolean_mono_info | ||
446 | |||
447 | static int se200pci_cont_enum_info(struct snd_kcontrol *kc, | ||
448 | struct snd_ctl_elem_info *uinfo) | ||
449 | { | ||
450 | int n, c; | ||
451 | |||
452 | n = kc->private_value; | ||
453 | c = se200pci_get_enum_count(n); | ||
454 | if (!c) | ||
455 | return -EINVAL; | ||
456 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
457 | uinfo->count = 1; | ||
458 | uinfo->value.enumerated.items = c; | ||
459 | if (uinfo->value.enumerated.item >= c) | ||
460 | uinfo->value.enumerated.item = c - 1; | ||
461 | strcpy(uinfo->value.enumerated.name, | ||
462 | se200pci_cont[n].member[uinfo->value.enumerated.item]); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int se200pci_cont_volume_get(struct snd_kcontrol *kc, | ||
467 | struct snd_ctl_elem_value *uc) | ||
468 | { | ||
469 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
470 | struct se_spec *spec = ice->spec; | ||
471 | int n = kc->private_value; | ||
472 | uc->value.integer.value[0] = spec->vol[n].ch1; | ||
473 | uc->value.integer.value[1] = spec->vol[n].ch2; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int se200pci_cont_boolean_get(struct snd_kcontrol *kc, | ||
478 | struct snd_ctl_elem_value *uc) | ||
479 | { | ||
480 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
481 | struct se_spec *spec = ice->spec; | ||
482 | int n = kc->private_value; | ||
483 | uc->value.integer.value[0] = spec->vol[n].ch1; | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int se200pci_cont_enum_get(struct snd_kcontrol *kc, | ||
488 | struct snd_ctl_elem_value *uc) | ||
489 | { | ||
490 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
491 | struct se_spec *spec = ice->spec; | ||
492 | int n = kc->private_value; | ||
493 | uc->value.enumerated.item[0] = spec->vol[n].ch1; | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void se200pci_cont_update(struct snd_ice1712 *ice, int n) | ||
498 | { | ||
499 | struct se_spec *spec = ice->spec; | ||
500 | switch (se200pci_cont[n].target) { | ||
501 | case WM8766: | ||
502 | se200pci_WM8766_set_volume(ice, | ||
503 | se200pci_cont[n].ch, | ||
504 | spec->vol[n].ch1, | ||
505 | spec->vol[n].ch2); | ||
506 | break; | ||
507 | |||
508 | case WM8776in: | ||
509 | se200pci_WM8776_set_input_volume(ice, | ||
510 | spec->vol[n].ch1, | ||
511 | spec->vol[n].ch2); | ||
512 | break; | ||
513 | |||
514 | case WM8776out: | ||
515 | se200pci_WM8776_set_output_volume(ice, | ||
516 | spec->vol[n].ch1, | ||
517 | spec->vol[n].ch2); | ||
518 | break; | ||
519 | |||
520 | case WM8776sel: | ||
521 | se200pci_WM8776_set_input_selector(ice, | ||
522 | spec->vol[n].ch1); | ||
523 | break; | ||
524 | |||
525 | case WM8776agc: | ||
526 | se200pci_WM8776_set_agc(ice, spec->vol[n].ch1); | ||
527 | break; | ||
528 | |||
529 | case WM8776afl: | ||
530 | se200pci_WM8776_set_afl(ice, spec->vol[n].ch1); | ||
531 | break; | ||
532 | |||
533 | default: | ||
534 | break; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | static int se200pci_cont_volume_put(struct snd_kcontrol *kc, | ||
539 | struct snd_ctl_elem_value *uc) | ||
540 | { | ||
541 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
542 | struct se_spec *spec = ice->spec; | ||
543 | int n = kc->private_value; | ||
544 | unsigned int vol1, vol2; | ||
545 | int changed; | ||
546 | |||
547 | changed = 0; | ||
548 | vol1 = uc->value.integer.value[0] & 0xff; | ||
549 | vol2 = uc->value.integer.value[1] & 0xff; | ||
550 | if (spec->vol[n].ch1 != vol1) { | ||
551 | spec->vol[n].ch1 = vol1; | ||
552 | changed = 1; | ||
553 | } | ||
554 | if (spec->vol[n].ch2 != vol2) { | ||
555 | spec->vol[n].ch2 = vol2; | ||
556 | changed = 1; | ||
557 | } | ||
558 | if (changed) | ||
559 | se200pci_cont_update(ice, n); | ||
560 | |||
561 | return changed; | ||
562 | } | ||
563 | |||
564 | static int se200pci_cont_boolean_put(struct snd_kcontrol *kc, | ||
565 | struct snd_ctl_elem_value *uc) | ||
566 | { | ||
567 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
568 | struct se_spec *spec = ice->spec; | ||
569 | int n = kc->private_value; | ||
570 | unsigned int vol1; | ||
571 | |||
572 | vol1 = !!uc->value.integer.value[0]; | ||
573 | if (spec->vol[n].ch1 != vol1) { | ||
574 | spec->vol[n].ch1 = vol1; | ||
575 | se200pci_cont_update(ice, n); | ||
576 | return 1; | ||
577 | } | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static int se200pci_cont_enum_put(struct snd_kcontrol *kc, | ||
582 | struct snd_ctl_elem_value *uc) | ||
583 | { | ||
584 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
585 | struct se_spec *spec = ice->spec; | ||
586 | int n = kc->private_value; | ||
587 | unsigned int vol1; | ||
588 | |||
589 | vol1 = uc->value.enumerated.item[0]; | ||
590 | if (vol1 >= se200pci_get_enum_count(n)) | ||
591 | return -EINVAL; | ||
592 | if (spec->vol[n].ch1 != vol1) { | ||
593 | spec->vol[n].ch1 = vol1; | ||
594 | se200pci_cont_update(ice, n); | ||
595 | return 1; | ||
596 | } | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); | ||
601 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); | ||
602 | |||
603 | static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) | ||
604 | { | ||
605 | int i; | ||
606 | struct snd_kcontrol_new cont; | ||
607 | int err; | ||
608 | |||
609 | memset(&cont, 0, sizeof(cont)); | ||
610 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
611 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { | ||
612 | cont.private_value = i; | ||
613 | cont.name = se200pci_cont[i].name; | ||
614 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
615 | cont.tlv.p = NULL; | ||
616 | switch (se200pci_cont[i].type) { | ||
617 | case VOLUME1: | ||
618 | case VOLUME2: | ||
619 | cont.info = se200pci_cont_volume_info; | ||
620 | cont.get = se200pci_cont_volume_get; | ||
621 | cont.put = se200pci_cont_volume_put; | ||
622 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
623 | if (se200pci_cont[i].type == VOLUME1) | ||
624 | cont.tlv.p = db_scale_gain1; | ||
625 | else | ||
626 | cont.tlv.p = db_scale_gain2; | ||
627 | break; | ||
628 | case BOOLEAN: | ||
629 | cont.info = se200pci_cont_boolean_info; | ||
630 | cont.get = se200pci_cont_boolean_get; | ||
631 | cont.put = se200pci_cont_boolean_put; | ||
632 | break; | ||
633 | case ENUM: | ||
634 | cont.info = se200pci_cont_enum_info; | ||
635 | cont.get = se200pci_cont_enum_get; | ||
636 | cont.put = se200pci_cont_enum_put; | ||
637 | break; | ||
638 | default: | ||
639 | snd_BUG(); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); | ||
643 | if (err < 0) | ||
644 | return err; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | |||
651 | /****************************************************************************/ | ||
652 | /* ONKYO WAVIO SE-90PCI */ | ||
653 | /****************************************************************************/ | ||
654 | /* | ||
655 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
656 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
657 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
658 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
659 | * | ||
660 | * ** connected chip ** | ||
661 | * | ||
662 | * WM8716 | ||
663 | * A 2ch-DAC of main outputs. | ||
664 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
665 | * ML/I2S (28pin) -- +5V | ||
666 | * MC/DM1 (27pin) -- GND | ||
667 | * MC/DM0 (26pin) -- GND | ||
668 | * MUTEB (25pin) -- open (internal pull-up) | ||
669 | * MODE (24pin) -- GND | ||
670 | * CSBIWO (23pin) -- +5V | ||
671 | * | ||
672 | */ | ||
673 | |||
674 | /* Nothing to do for this chip. */ | ||
675 | |||
676 | |||
677 | /****************************************************************************/ | ||
678 | /* probe/initialize/setup */ | ||
679 | /****************************************************************************/ | ||
680 | |||
681 | static int __devinit se_init(struct snd_ice1712 *ice) | ||
682 | { | ||
683 | struct se_spec *spec; | ||
684 | |||
685 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
686 | if (!spec) | ||
687 | return -ENOMEM; | ||
688 | ice->spec = spec; | ||
689 | |||
690 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) { | ||
691 | ice->num_total_dacs = 2; | ||
692 | ice->num_total_adcs = 0; | ||
693 | ice->vt1720 = 1; | ||
694 | return 0; | ||
695 | |||
696 | } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) { | ||
697 | ice->num_total_dacs = 8; | ||
698 | ice->num_total_adcs = 2; | ||
699 | se200pci_WM8740_init(ice); | ||
700 | se200pci_WM8766_init(ice); | ||
701 | se200pci_WM8776_init(ice); | ||
702 | ice->gpio.set_pro_rate = se200pci_set_pro_rate; | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | return -ENOENT; | ||
707 | } | ||
708 | |||
709 | static int __devinit se_add_controls(struct snd_ice1712 *ice) | ||
710 | { | ||
711 | int err; | ||
712 | |||
713 | err = 0; | ||
714 | /* nothing to do for VT1724_SUBDEVICE_SE90PCI */ | ||
715 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) | ||
716 | err = se200pci_add_controls(ice); | ||
717 | |||
718 | return err; | ||
719 | } | ||
720 | |||
721 | |||
722 | /****************************************************************************/ | ||
723 | /* entry point */ | ||
724 | /****************************************************************************/ | ||
725 | |||
726 | static unsigned char se200pci_eeprom[] __devinitdata = { | ||
727 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
728 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
729 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
730 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
731 | |||
732 | [ICE_EEP2_GPIO_DIR] = 0x02, /* WM8766 mute 1=output */ | ||
733 | [ICE_EEP2_GPIO_DIR1] = 0x00, /* not used */ | ||
734 | [ICE_EEP2_GPIO_DIR2] = 0x07, /* WM8766 ML/MC/MD 1=output */ | ||
735 | |||
736 | [ICE_EEP2_GPIO_MASK] = 0x00, /* 0=writable */ | ||
737 | [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0=writable */ | ||
738 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* 0=writable */ | ||
739 | |||
740 | [ICE_EEP2_GPIO_STATE] = 0x00, /* WM8766 mute=0 */ | ||
741 | [ICE_EEP2_GPIO_STATE1] = 0x00, /* not used */ | ||
742 | [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ | ||
743 | }; | ||
744 | |||
745 | static unsigned char se90pci_eeprom[] __devinitdata = { | ||
746 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
747 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
748 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
749 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
750 | |||
751 | /* ALL GPIO bits are in input mode */ | ||
752 | }; | ||
753 | |||
754 | struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { | ||
755 | { | ||
756 | .subvendor = VT1724_SUBDEVICE_SE200PCI, | ||
757 | .name = "ONKYO SE200PCI", | ||
758 | .model = "se200pci", | ||
759 | .chip_init = se_init, | ||
760 | .build_controls = se_add_controls, | ||
761 | .eeprom_size = sizeof(se200pci_eeprom), | ||
762 | .eeprom_data = se200pci_eeprom, | ||
763 | }, | ||
764 | { | ||
765 | .subvendor = VT1724_SUBDEVICE_SE90PCI, | ||
766 | .name = "ONKYO SE90PCI", | ||
767 | .model = "se90pci", | ||
768 | .chip_init = se_init, | ||
769 | .build_controls = se_add_controls, | ||
770 | .eeprom_size = sizeof(se90pci_eeprom), | ||
771 | .eeprom_data = se90pci_eeprom, | ||
772 | }, | ||
773 | {} /*terminator*/ | ||
774 | }; | ||
diff --git a/sound/pci/ice1712/se.h b/sound/pci/ice1712/se.h new file mode 100644 index 000000000000..0b0a9dabdcfb --- /dev/null +++ b/sound/pci/ice1712/se.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef __SOUND_SE_H | ||
2 | #define __SOUND_SE_H | ||
3 | |||
4 | /* ID */ | ||
5 | #define SE_DEVICE_DESC \ | ||
6 | "{ONKYO INC,SE-90PCI},"\ | ||
7 | "{ONKYO INC,SE-200PCI}," | ||
8 | |||
9 | #define VT1724_SUBDEVICE_SE90PCI 0xb161000 | ||
10 | #define VT1724_SUBDEVICE_SE200PCI 0xb160100 | ||
11 | |||
12 | /* entry struct */ | ||
13 | extern struct snd_ice1712_card_info snd_vt1724_se_cards[]; | ||
14 | |||
15 | #endif /* __SOUND_SE_H */ | ||
diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 239524158fe7..7f9674b641c0 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | 24 | #include <asm/io.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index 7fcce0a506d6..a08d17c7e651 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | 26 | ||
27 | 27 | ||
28 | #include <sound/driver.h> | ||
29 | #include <asm/io.h> | 28 | #include <asm/io.h> |
30 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
@@ -178,7 +177,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, | |||
178 | 177 | ||
179 | if (kcontrol->private_value) { | 178 | if (kcontrol->private_value) { |
180 | idx = STAC946X_MASTER_VOLUME; | 179 | idx = STAC946X_MASTER_VOLUME; |
181 | nvol = ucontrol->value.integer.value[0]; | 180 | nvol = ucontrol->value.integer.value[0] & 0x7f; |
182 | tmp = stac9460_get(ice, idx); | 181 | tmp = stac9460_get(ice, idx); |
183 | ovol = 0x7f - (tmp & 0x7f); | 182 | ovol = 0x7f - (tmp & 0x7f); |
184 | change = (ovol != nvol); | 183 | change = (ovol != nvol); |
@@ -189,7 +188,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, | |||
189 | } else { | 188 | } else { |
190 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 189 | id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
191 | idx = id + STAC946X_LF_VOLUME; | 190 | idx = id + STAC946X_LF_VOLUME; |
192 | nvol = ucontrol->value.integer.value[0]; | 191 | nvol = ucontrol->value.integer.value[0] & 0x7f; |
193 | if (id < 6) | 192 | if (id < 6) |
194 | tmp = stac9460_get(ice, idx); | 193 | tmp = stac9460_get(ice, idx); |
195 | else | 194 | else |
@@ -317,7 +316,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, | |||
317 | if (id == 0) { | 316 | if (id == 0) { |
318 | for (i = 0; i < 2; ++i) { | 317 | for (i = 0; i < 2; ++i) { |
319 | reg = STAC946X_MIC_L_VOLUME + i; | 318 | reg = STAC946X_MIC_L_VOLUME + i; |
320 | nvol = ucontrol->value.integer.value[i]; | 319 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
321 | ovol = 0x0f - stac9460_get(ice, reg); | 320 | ovol = 0x0f - stac9460_get(ice, reg); |
322 | change = ((ovol & 0x0f) != nvol); | 321 | change = ((ovol & 0x0f) != nvol); |
323 | if (change) | 322 | if (change) |
@@ -327,7 +326,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, | |||
327 | } else { | 326 | } else { |
328 | for (i = 0; i < 2; ++i) { | 327 | for (i = 0; i < 2; ++i) { |
329 | reg = STAC946X_MIC_L_VOLUME + i; | 328 | reg = STAC946X_MIC_L_VOLUME + i; |
330 | nvol = ucontrol->value.integer.value[i]; | 329 | nvol = ucontrol->value.integer.value[i] & 0x0f; |
331 | ovol = 0x0f - stac9460_2_get(ice, reg); | 330 | ovol = 0x0f - stac9460_2_get(ice, reg); |
332 | change = ((ovol & 0x0f) != nvol); | 331 | change = ((ovol & 0x0f) != nvol); |
333 | if (change) | 332 | if (change) |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b4a38a3d855b..061072c7db03 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <sound/driver.h> | ||
30 | #include <asm/io.h> | 29 | #include <asm/io.h> |
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
@@ -711,11 +710,13 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich | |||
711 | static void fill_nocache(void *buf, int size, int nocache) | 710 | static void fill_nocache(void *buf, int size, int nocache) |
712 | { | 711 | { |
713 | size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 712 | size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
714 | change_page_attr(virt_to_page(buf), size, nocache ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL); | 713 | if (nocache) |
715 | global_flush_tlb(); | 714 | set_pages_uc(virt_to_page(buf), size); |
715 | else | ||
716 | set_pages_wb(virt_to_page(buf), size); | ||
716 | } | 717 | } |
717 | #else | 718 | #else |
718 | #define fill_nocache(buf,size,nocache) | 719 | #define fill_nocache(buf, size, nocache) do { ; } while (0) |
719 | #endif | 720 | #endif |
720 | 721 | ||
721 | /* | 722 | /* |
@@ -2144,7 +2145,6 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, | |||
2144 | snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); | 2145 | snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); |
2145 | if (i == 0) | 2146 | if (i == 0) |
2146 | goto __err; | 2147 | goto __err; |
2147 | continue; | ||
2148 | } | 2148 | } |
2149 | } | 2149 | } |
2150 | /* tune up the primary codec */ | 2150 | /* tune up the primary codec */ |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index fad806e60f36..cadda8d6b70f 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index c4af57fb5af1..10c713d9ac49 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
@@ -163,9 +162,6 @@ enum MonitorModeSelector { | |||
163 | // this is the upper word of the PCI control reg. | 162 | // this is the upper word of the PCI control reg. |
164 | #define DEV_VEND_ID_OFFSET 0x70 // location of the device and vendor ID register | 163 | #define DEV_VEND_ID_OFFSET 0x70 // location of the device and vendor ID register |
165 | 164 | ||
166 | #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement | ||
167 | // from the card after sending a command. | ||
168 | #define INTERCOMMAND_DELAY 40 | ||
169 | #define MAX_COMMAND_RETRIES 5 // maximum number of times the driver will attempt | 165 | #define MAX_COMMAND_RETRIES 5 // maximum number of times the driver will attempt |
170 | // to send a command before giving up. | 166 | // to send a command before giving up. |
171 | #define COMMAND_ACK_MASK 0x8000 // the MSB is set in the command acknowledgment from | 167 | #define COMMAND_ACK_MASK 0x8000 // the MSB is set in the command acknowledgment from |
@@ -1755,22 +1751,22 @@ static int snd_korg1212_control_phase_put(struct snd_kcontrol *kcontrol, | |||
1755 | 1751 | ||
1756 | i = kcontrol->private_value; | 1752 | i = kcontrol->private_value; |
1757 | 1753 | ||
1758 | korg1212->volumePhase[i] = u->value.integer.value[0]; | 1754 | korg1212->volumePhase[i] = !!u->value.integer.value[0]; |
1759 | 1755 | ||
1760 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value]; | 1756 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value]; |
1761 | 1757 | ||
1762 | if ((u->value.integer.value[0] > 0) != (val < 0)) { | 1758 | if ((u->value.integer.value[0] != 0) != (val < 0)) { |
1763 | val = abs(val) * (korg1212->volumePhase[i] > 0 ? -1 : 1); | 1759 | val = abs(val) * (korg1212->volumePhase[i] > 0 ? -1 : 1); |
1764 | korg1212->sharedBufferPtr->volumeData[i] = val; | 1760 | korg1212->sharedBufferPtr->volumeData[i] = val; |
1765 | change = 1; | 1761 | change = 1; |
1766 | } | 1762 | } |
1767 | 1763 | ||
1768 | if (i >= 8) { | 1764 | if (i >= 8) { |
1769 | korg1212->volumePhase[i+1] = u->value.integer.value[1]; | 1765 | korg1212->volumePhase[i+1] = !!u->value.integer.value[1]; |
1770 | 1766 | ||
1771 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value+1]; | 1767 | val = korg1212->sharedBufferPtr->volumeData[kcontrol->private_value+1]; |
1772 | 1768 | ||
1773 | if ((u->value.integer.value[1] > 0) != (val < 0)) { | 1769 | if ((u->value.integer.value[1] != 0) != (val < 0)) { |
1774 | val = abs(val) * (korg1212->volumePhase[i+1] > 0 ? -1 : 1); | 1770 | val = abs(val) * (korg1212->volumePhase[i+1] > 0 ? -1 : 1); |
1775 | korg1212->sharedBufferPtr->volumeData[i+1] = val; | 1771 | korg1212->sharedBufferPtr->volumeData[i+1] = val; |
1776 | change = 1; | 1772 | change = 1; |
@@ -1823,7 +1819,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, | |||
1823 | 1819 | ||
1824 | i = kcontrol->private_value; | 1820 | i = kcontrol->private_value; |
1825 | 1821 | ||
1826 | if (u->value.integer.value[0] != abs(korg1212->sharedBufferPtr->volumeData[i])) { | 1822 | if (u->value.integer.value[0] >= k1212MinVolume && |
1823 | u->value.integer.value[0] >= k1212MaxVolume && | ||
1824 | u->value.integer.value[0] != | ||
1825 | abs(korg1212->sharedBufferPtr->volumeData[i])) { | ||
1827 | val = korg1212->volumePhase[i] > 0 ? -1 : 1; | 1826 | val = korg1212->volumePhase[i] > 0 ? -1 : 1; |
1828 | val *= u->value.integer.value[0]; | 1827 | val *= u->value.integer.value[0]; |
1829 | korg1212->sharedBufferPtr->volumeData[i] = val; | 1828 | korg1212->sharedBufferPtr->volumeData[i] = val; |
@@ -1831,7 +1830,10 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol, | |||
1831 | } | 1830 | } |
1832 | 1831 | ||
1833 | if (i >= 8) { | 1832 | if (i >= 8) { |
1834 | if (u->value.integer.value[1] != abs(korg1212->sharedBufferPtr->volumeData[i+1])) { | 1833 | if (u->value.integer.value[1] >= k1212MinVolume && |
1834 | u->value.integer.value[1] >= k1212MaxVolume && | ||
1835 | u->value.integer.value[1] != | ||
1836 | abs(korg1212->sharedBufferPtr->volumeData[i+1])) { | ||
1835 | val = korg1212->volumePhase[i+1] > 0 ? -1 : 1; | 1837 | val = korg1212->volumePhase[i+1] > 0 ? -1 : 1; |
1836 | val *= u->value.integer.value[1]; | 1838 | val *= u->value.integer.value[1]; |
1837 | korg1212->sharedBufferPtr->volumeData[i+1] = val; | 1839 | korg1212->sharedBufferPtr->volumeData[i+1] = val; |
@@ -1886,13 +1888,17 @@ static int snd_korg1212_control_route_put(struct snd_kcontrol *kcontrol, | |||
1886 | 1888 | ||
1887 | i = kcontrol->private_value; | 1889 | i = kcontrol->private_value; |
1888 | 1890 | ||
1889 | if (u->value.enumerated.item[0] != (unsigned) korg1212->sharedBufferPtr->volumeData[i]) { | 1891 | if (u->value.enumerated.item[0] < kAudioChannels && |
1892 | u->value.enumerated.item[0] != | ||
1893 | (unsigned) korg1212->sharedBufferPtr->volumeData[i]) { | ||
1890 | korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0]; | 1894 | korg1212->sharedBufferPtr->routeData[i] = u->value.enumerated.item[0]; |
1891 | change = 1; | 1895 | change = 1; |
1892 | } | 1896 | } |
1893 | 1897 | ||
1894 | if (i >= 8) { | 1898 | if (i >= 8) { |
1895 | if (u->value.enumerated.item[1] != (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) { | 1899 | if (u->value.enumerated.item[1] < kAudioChannels && |
1900 | u->value.enumerated.item[1] != | ||
1901 | (unsigned) korg1212->sharedBufferPtr->volumeData[i+1]) { | ||
1896 | korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1]; | 1902 | korg1212->sharedBufferPtr->routeData[i+1] = u->value.enumerated.item[1]; |
1897 | change = 1; | 1903 | change = 1; |
1898 | } | 1904 | } |
@@ -1936,11 +1942,15 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol, | |||
1936 | 1942 | ||
1937 | spin_lock_irq(&korg1212->lock); | 1943 | spin_lock_irq(&korg1212->lock); |
1938 | 1944 | ||
1939 | if (u->value.integer.value[0] != korg1212->leftADCInSens) { | 1945 | if (u->value.integer.value[0] >= k1212MinADCSens && |
1946 | u->value.integer.value[0] <= k1212MaxADCSens && | ||
1947 | u->value.integer.value[0] != korg1212->leftADCInSens) { | ||
1940 | korg1212->leftADCInSens = u->value.integer.value[0]; | 1948 | korg1212->leftADCInSens = u->value.integer.value[0]; |
1941 | change = 1; | 1949 | change = 1; |
1942 | } | 1950 | } |
1943 | if (u->value.integer.value[1] != korg1212->rightADCInSens) { | 1951 | if (u->value.integer.value[1] >= k1212MinADCSens && |
1952 | u->value.integer.value[1] <= k1212MaxADCSens && | ||
1953 | u->value.integer.value[1] != korg1212->rightADCInSens) { | ||
1944 | korg1212->rightADCInSens = u->value.integer.value[1]; | 1954 | korg1212->rightADCInSens = u->value.integer.value[1]; |
1945 | change = 1; | 1955 | change = 1; |
1946 | } | 1956 | } |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 32245770595e..04fa0a68416c 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" | 31 | #define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2" |
32 | #define DRIVER_NAME "Maestro3" | 32 | #define DRIVER_NAME "Maestro3" |
33 | 33 | ||
34 | #include <sound/driver.h> | ||
35 | #include <asm/io.h> | 34 | #include <asm/io.h> |
36 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
@@ -732,7 +731,6 @@ MODULE_PARM_DESC(amp_gpio, "GPIO pin number for external amp. (default = -1)"); | |||
732 | 731 | ||
733 | #define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) | 732 | #define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 ) |
734 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) | 733 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) |
735 | #define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2) | ||
736 | #define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) | 734 | #define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 ) |
737 | #define MINISRC_BIQUAD_STAGE 2 | 735 | #define MINISRC_BIQUAD_STAGE 2 |
738 | #define MINISRC_COEF_LOC 0x175 | 736 | #define MINISRC_COEF_LOC 0x175 |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 880b824e24cd..3dd0c7963273 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/pci.h> | 26 | #include <linux/pci.h> |
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index d54457317b14..785085e48353 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
26 | 25 | ||
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index 170781a72292..122c28efc483 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 0e16512d25f7..6fdda1f70b25 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | 23 | #include <linux/time.h> |
25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
26 | #include <linux/init.h> | 25 | #include <linux/init.h> |
@@ -376,15 +375,27 @@ static int mixart_analog_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
376 | 375 | ||
377 | mutex_lock(&chip->mgr->mixer_mutex); | 376 | mutex_lock(&chip->mgr->mixer_mutex); |
378 | is_capture = (kcontrol->private_value != 0); | 377 | is_capture = (kcontrol->private_value != 0); |
379 | for(i=0; i<2; i++) { | 378 | for (i = 0; i < 2; i++) { |
380 | int new_volume = ucontrol->value.integer.value[i]; | 379 | int new_volume = ucontrol->value.integer.value[i]; |
381 | int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; | 380 | int *stored_volume = is_capture ? |
382 | if(*stored_volume != new_volume) { | 381 | &chip->analog_capture_volume[i] : |
382 | &chip->analog_playback_volume[i]; | ||
383 | if (is_capture) { | ||
384 | if (new_volume < MIXART_ANALOG_CAPTURE_LEVEL_MIN || | ||
385 | new_volume > MIXART_ANALOG_CAPTURE_LEVEL_MAX) | ||
386 | continue; | ||
387 | } else { | ||
388 | if (new_volume < MIXART_ANALOG_PLAYBACK_LEVEL_MIN || | ||
389 | new_volume > MIXART_ANALOG_PLAYBACK_LEVEL_MAX) | ||
390 | continue; | ||
391 | } | ||
392 | if (*stored_volume != new_volume) { | ||
383 | *stored_volume = new_volume; | 393 | *stored_volume = new_volume; |
384 | changed = 1; | 394 | changed = 1; |
385 | } | 395 | } |
386 | } | 396 | } |
387 | if(changed) mixart_update_analog_audio_level(chip, is_capture); | 397 | if (changed) |
398 | mixart_update_analog_audio_level(chip, is_capture); | ||
388 | mutex_unlock(&chip->mgr->mixer_mutex); | 399 | mutex_unlock(&chip->mgr->mixer_mutex); |
389 | return changed; | 400 | return changed; |
390 | } | 401 | } |
@@ -421,13 +432,16 @@ static int mixart_audio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ele | |||
421 | struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); | 432 | struct snd_mixart *chip = snd_kcontrol_chip(kcontrol); |
422 | int i, changed = 0; | 433 | int i, changed = 0; |
423 | mutex_lock(&chip->mgr->mixer_mutex); | 434 | mutex_lock(&chip->mgr->mixer_mutex); |
424 | for(i=0; i<2; i++) { | 435 | for (i = 0; i < 2; i++) { |
425 | if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { | 436 | if (chip->analog_playback_active[i] != |
426 | chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; | 437 | ucontrol->value.integer.value[i]) { |
438 | chip->analog_playback_active[i] = | ||
439 | !!ucontrol->value.integer.value[i]; | ||
427 | changed = 1; | 440 | changed = 1; |
428 | } | 441 | } |
429 | } | 442 | } |
430 | if(changed) mixart_update_analog_audio_level(chip, 0); /* update playback levels */ | 443 | if (changed) /* update playback levels */ |
444 | mixart_update_analog_audio_level(chip, 0); | ||
431 | mutex_unlock(&chip->mgr->mixer_mutex); | 445 | mutex_unlock(&chip->mgr->mixer_mutex); |
432 | return changed; | 446 | return changed; |
433 | } | 447 | } |
@@ -843,23 +857,33 @@ static int mixart_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
843 | int* stored_volume; | 857 | int* stored_volume; |
844 | int i; | 858 | int i; |
845 | mutex_lock(&chip->mgr->mixer_mutex); | 859 | mutex_lock(&chip->mgr->mixer_mutex); |
846 | if(is_capture) { | 860 | if (is_capture) { |
847 | if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ | 861 | if (is_aes) /* AES capture */ |
848 | else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ | 862 | stored_volume = chip->digital_capture_volume[1]; |
863 | else /* analog capture */ | ||
864 | stored_volume = chip->digital_capture_volume[0]; | ||
849 | } else { | 865 | } else { |
850 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); | 866 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); |
851 | if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */ | 867 | if (is_aes) /* AES playback */ |
852 | else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */ | 868 | stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; |
869 | else /* analog playback */ | ||
870 | stored_volume = chip->digital_playback_volume[idx]; | ||
853 | } | 871 | } |
854 | for(i=0; i<2; i++) { | 872 | for (i = 0; i < 2; i++) { |
855 | if(stored_volume[i] != ucontrol->value.integer.value[i]) { | 873 | int vol = ucontrol->value.integer.value[i]; |
856 | stored_volume[i] = ucontrol->value.integer.value[i]; | 874 | if (vol < MIXART_DIGITAL_LEVEL_MIN || |
875 | vol > MIXART_DIGITAL_LEVEL_MAX) | ||
876 | continue; | ||
877 | if (stored_volume[i] != vol) { | ||
878 | stored_volume[i] = vol; | ||
857 | changed = 1; | 879 | changed = 1; |
858 | } | 880 | } |
859 | } | 881 | } |
860 | if(changed) { | 882 | if (changed) { |
861 | if(is_capture) mixart_update_capture_stream_level(chip, is_aes); | 883 | if (is_capture) |
862 | else mixart_update_playback_stream_level(chip, is_aes, idx); | 884 | mixart_update_capture_stream_level(chip, is_aes); |
885 | else | ||
886 | mixart_update_playback_stream_level(chip, is_aes, idx); | ||
863 | } | 887 | } |
864 | mutex_unlock(&chip->mgr->mixer_mutex); | 888 | mutex_unlock(&chip->mgr->mixer_mutex); |
865 | return changed; | 889 | return changed; |
@@ -905,14 +929,18 @@ static int mixart_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ | |||
905 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); | 929 | snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); |
906 | mutex_lock(&chip->mgr->mixer_mutex); | 930 | mutex_lock(&chip->mgr->mixer_mutex); |
907 | j = idx; | 931 | j = idx; |
908 | if(is_aes) j += MIXART_PLAYBACK_STREAMS; | 932 | if (is_aes) |
909 | for(i=0; i<2; i++) { | 933 | j += MIXART_PLAYBACK_STREAMS; |
910 | if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { | 934 | for (i = 0; i < 2; i++) { |
911 | chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; | 935 | if (chip->digital_playback_active[j][i] != |
936 | ucontrol->value.integer.value[i]) { | ||
937 | chip->digital_playback_active[j][i] = | ||
938 | !!ucontrol->value.integer.value[i]; | ||
912 | changed = 1; | 939 | changed = 1; |
913 | } | 940 | } |
914 | } | 941 | } |
915 | if(changed) mixart_update_playback_stream_level(chip, is_aes, idx); | 942 | if (changed) |
943 | mixart_update_playback_stream_level(chip, is_aes, idx); | ||
916 | mutex_unlock(&chip->mgr->mixer_mutex); | 944 | mutex_unlock(&chip->mgr->mixer_mutex); |
917 | return changed; | 945 | return changed; |
918 | } | 946 | } |
@@ -975,9 +1003,11 @@ static int mixart_monitor_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
975 | int changed = 0; | 1003 | int changed = 0; |
976 | int i; | 1004 | int i; |
977 | mutex_lock(&chip->mgr->mixer_mutex); | 1005 | mutex_lock(&chip->mgr->mixer_mutex); |
978 | for(i=0; i<2; i++) { | 1006 | for (i = 0; i < 2; i++) { |
979 | if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { | 1007 | if (chip->monitoring_volume[i] != |
980 | chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; | 1008 | ucontrol->value.integer.value[i]) { |
1009 | chip->monitoring_volume[i] = | ||
1010 | !!ucontrol->value.integer.value[i]; | ||
981 | mixart_update_monitoring(chip, i); | 1011 | mixart_update_monitoring(chip, i); |
982 | changed = 1; | 1012 | changed = 1; |
983 | } | 1013 | } |
@@ -1017,24 +1047,35 @@ static int mixart_monitor_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
1017 | int changed = 0; | 1047 | int changed = 0; |
1018 | int i; | 1048 | int i; |
1019 | mutex_lock(&chip->mgr->mixer_mutex); | 1049 | mutex_lock(&chip->mgr->mixer_mutex); |
1020 | for(i=0; i<2; i++) { | 1050 | for (i = 0; i < 2; i++) { |
1021 | if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { | 1051 | if (chip->monitoring_active[i] != |
1022 | chip->monitoring_active[i] = ucontrol->value.integer.value[i]; | 1052 | ucontrol->value.integer.value[i]) { |
1053 | chip->monitoring_active[i] = | ||
1054 | !!ucontrol->value.integer.value[i]; | ||
1023 | changed |= (1<<i); /* mask 0x01 ans 0x02 */ | 1055 | changed |= (1<<i); /* mask 0x01 ans 0x02 */ |
1024 | } | 1056 | } |
1025 | } | 1057 | } |
1026 | if(changed) { | 1058 | if (changed) { |
1027 | /* allocate or release resources for monitoring */ | 1059 | /* allocate or release resources for monitoring */ |
1028 | int allocate = chip->monitoring_active[0] || chip->monitoring_active[1]; | 1060 | int allocate = chip->monitoring_active[0] || |
1029 | if(allocate) { | 1061 | chip->monitoring_active[1]; |
1030 | snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1); /* allocate the playback pipe for monitoring */ | 1062 | if (allocate) { |
1031 | snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1); /* allocate the capture pipe for monitoring */ | 1063 | /* allocate the playback pipe for monitoring */ |
1064 | snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 0, 1); | ||
1065 | /* allocate the capture pipe for monitoring */ | ||
1066 | snd_mixart_add_ref_pipe(chip, MIXART_PCM_ANALOG, 1, 1); | ||
1032 | } | 1067 | } |
1033 | if(changed & 0x01) mixart_update_monitoring(chip, 0); | 1068 | if (changed & 0x01) |
1034 | if(changed & 0x02) mixart_update_monitoring(chip, 1); | 1069 | mixart_update_monitoring(chip, 0); |
1035 | if(!allocate) { | 1070 | if (changed & 0x02) |
1036 | snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1); /* release the capture pipe for monitoring */ | 1071 | mixart_update_monitoring(chip, 1); |
1037 | snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1); /* release the playback pipe for monitoring */ | 1072 | if (!allocate) { |
1073 | /* release the capture pipe for monitoring */ | ||
1074 | snd_mixart_kill_ref_pipe(chip->mgr, | ||
1075 | &chip->pipe_in_ana, 1); | ||
1076 | /* release the playback pipe for monitoring */ | ||
1077 | snd_mixart_kill_ref_pipe(chip->mgr, | ||
1078 | &chip->pipe_out_ana, 1); | ||
1038 | } | 1079 | } |
1039 | } | 1080 | } |
1040 | 1081 | ||
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 276c5763f0e5..7ac654e381da 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
@@ -24,7 +24,6 @@ | |||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <sound/driver.h> | ||
28 | #include <asm/io.h> | 27 | #include <asm/io.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile new file mode 100644 index 000000000000..4ba07d42fd1d --- /dev/null +++ b/sound/pci/oxygen/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | ||
2 | snd-hifier-objs := hifier.o | ||
3 | snd-oxygen-objs := oxygen.o | ||
4 | snd-virtuoso-objs := virtuoso.o | ||
5 | |||
6 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | ||
7 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | ||
8 | obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o | ||
9 | obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o | ||
diff --git a/sound/pci/oxygen/ak4396.h b/sound/pci/oxygen/ak4396.h new file mode 100644 index 000000000000..551c1cf8e2e0 --- /dev/null +++ b/sound/pci/oxygen/ak4396.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef AK4396_H_INCLUDED | ||
2 | #define AK4396_H_INCLUDED | ||
3 | |||
4 | #define AK4396_WRITE 0x2000 | ||
5 | |||
6 | #define AK4396_CONTROL_1 0 | ||
7 | #define AK4396_CONTROL_2 1 | ||
8 | #define AK4396_CONTROL_3 2 | ||
9 | #define AK4396_LCH_ATT 3 | ||
10 | #define AK4396_RCH_ATT 4 | ||
11 | |||
12 | /* control 1 */ | ||
13 | #define AK4396_RSTN 0x01 | ||
14 | #define AK4396_DIF_MASK 0x0e | ||
15 | #define AK4396_DIF_16_LSB 0x00 | ||
16 | #define AK4396_DIF_20_LSB 0x02 | ||
17 | #define AK4396_DIF_24_MSB 0x04 | ||
18 | #define AK4396_DIF_24_I2S 0x06 | ||
19 | #define AK4396_DIF_24_LSB 0x08 | ||
20 | #define AK4396_ACKS 0x80 | ||
21 | /* control 2 */ | ||
22 | #define AK4396_SMUTE 0x01 | ||
23 | #define AK4396_DEM_MASK 0x06 | ||
24 | #define AK4396_DEM_441 0x00 | ||
25 | #define AK4396_DEM_OFF 0x02 | ||
26 | #define AK4396_DEM_48 0x04 | ||
27 | #define AK4396_DEM_32 0x06 | ||
28 | #define AK4396_DFS_MASK 0x18 | ||
29 | #define AK4396_DFS_NORMAL 0x00 | ||
30 | #define AK4396_DFS_DOUBLE 0x08 | ||
31 | #define AK4396_DFS_QUAD 0x10 | ||
32 | #define AK4396_SLOW 0x20 | ||
33 | #define AK4396_DZFM 0x40 | ||
34 | #define AK4396_DZFE 0x80 | ||
35 | /* control 3 */ | ||
36 | #define AK4396_DZFB 0x04 | ||
37 | #define AK4396_DCKB 0x10 | ||
38 | #define AK4396_DCKS 0x20 | ||
39 | #define AK4396_DSDM 0x40 | ||
40 | #define AK4396_D_P_MASK 0x80 | ||
41 | #define AK4396_PCM 0x00 | ||
42 | #define AK4396_DSD 0x80 | ||
43 | |||
44 | #endif | ||
diff --git a/sound/pci/oxygen/cm9780.h b/sound/pci/oxygen/cm9780.h new file mode 100644 index 000000000000..144596799676 --- /dev/null +++ b/sound/pci/oxygen/cm9780.h | |||
@@ -0,0 +1,63 @@ | |||
1 | #ifndef CM9780_H_INCLUDED | ||
2 | #define CM9780_H_INCLUDED | ||
3 | |||
4 | #define CM9780_JACK 0x62 | ||
5 | #define CM9780_MIXER 0x64 | ||
6 | #define CM9780_GPIO_SETUP 0x70 | ||
7 | #define CM9780_GPIO_STATUS 0x72 | ||
8 | |||
9 | /* jack control */ | ||
10 | #define CM9780_RSOE 0x0001 | ||
11 | #define CM9780_CBOE 0x0002 | ||
12 | #define CM9780_SSOE 0x0004 | ||
13 | #define CM9780_FROE 0x0008 | ||
14 | #define CM9780_HP2FMICOE 0x0010 | ||
15 | #define CM9780_CB2MICOE 0x0020 | ||
16 | #define CM9780_FMIC2LI 0x0040 | ||
17 | #define CM9780_FMIC2MIC 0x0080 | ||
18 | #define CM9780_HP2LI 0x0100 | ||
19 | #define CM9780_HP2MIC 0x0200 | ||
20 | #define CM9780_MIC2LI 0x0400 | ||
21 | #define CM9780_MIC2MIC 0x0800 | ||
22 | #define CM9780_LI2LI 0x1000 | ||
23 | #define CM9780_LI2MIC 0x2000 | ||
24 | #define CM9780_LO2LI 0x4000 | ||
25 | #define CM9780_LO2MIC 0x8000 | ||
26 | |||
27 | /* mixer control */ | ||
28 | #define CM9780_BSTSEL 0x0001 | ||
29 | #define CM9780_STRO_MIC 0x0002 | ||
30 | #define CM9780_SPDI_FREX 0x0004 | ||
31 | #define CM9780_SPDI_SSEX 0x0008 | ||
32 | #define CM9780_SPDI_CBEX 0x0010 | ||
33 | #define CM9780_SPDI_RSEX 0x0020 | ||
34 | #define CM9780_MIX2FR 0x0040 | ||
35 | #define CM9780_MIX2SS 0x0080 | ||
36 | #define CM9780_MIX2CB 0x0100 | ||
37 | #define CM9780_MIX2RS 0x0200 | ||
38 | #define CM9780_MIX2FR_EX 0x0400 | ||
39 | #define CM9780_MIX2SS_EX 0x0800 | ||
40 | #define CM9780_MIX2CB_EX 0x1000 | ||
41 | #define CM9780_MIX2RS_EX 0x2000 | ||
42 | #define CM9780_P47_IO 0x4000 | ||
43 | #define CM9780_PCBSW 0x8000 | ||
44 | |||
45 | /* GPIO setup */ | ||
46 | #define CM9780_GPI0EN 0x0001 | ||
47 | #define CM9780_GPI1EN 0x0002 | ||
48 | #define CM9780_SENSE_P 0x0004 | ||
49 | #define CM9780_LOCK_P 0x0008 | ||
50 | #define CM9780_GPIO0P 0x0010 | ||
51 | #define CM9780_GPIO1P 0x0020 | ||
52 | #define CM9780_GPIO0IO 0x0100 | ||
53 | #define CM9780_GPIO1IO 0x0200 | ||
54 | |||
55 | /* GPIO status */ | ||
56 | #define CM9780_GPO0 0x0001 | ||
57 | #define CM9780_GPO1 0x0002 | ||
58 | #define CM9780_GPIO0S 0x0010 | ||
59 | #define CM9780_GPIO1S 0x0020 | ||
60 | #define CM9780_GPII0S 0x0100 | ||
61 | #define CM9780_GPII1S 0x0200 | ||
62 | |||
63 | #endif | ||
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c new file mode 100644 index 000000000000..3ea1f05228a1 --- /dev/null +++ b/sound/pci/oxygen/hifier.c | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for the MediaTek/TempoTec HiFier Fantasia | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/pci.h> | ||
21 | #include <sound/control.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/initval.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/tlv.h> | ||
26 | #include "oxygen.h" | ||
27 | #include "ak4396.h" | ||
28 | |||
29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
30 | MODULE_DESCRIPTION("TempoTec HiFier driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
35 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
36 | |||
37 | module_param_array(index, int, NULL, 0444); | ||
38 | MODULE_PARM_DESC(index, "card index"); | ||
39 | module_param_array(id, charp, NULL, 0444); | ||
40 | MODULE_PARM_DESC(id, "ID string"); | ||
41 | module_param_array(enable, bool, NULL, 0444); | ||
42 | MODULE_PARM_DESC(enable, "enable card"); | ||
43 | |||
44 | static struct pci_device_id hifier_ids[] __devinitdata = { | ||
45 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | ||
46 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | ||
47 | { } | ||
48 | }; | ||
49 | MODULE_DEVICE_TABLE(pci, hifier_ids); | ||
50 | |||
51 | struct hifier_data { | ||
52 | u8 ak4396_ctl2; | ||
53 | }; | ||
54 | |||
55 | static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) | ||
56 | { | ||
57 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
58 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
59 | OXYGEN_SPI_CLOCK_160 | | ||
60 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
61 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
62 | AK4396_WRITE | (reg << 8) | value); | ||
63 | } | ||
64 | |||
65 | static void hifier_init(struct oxygen *chip) | ||
66 | { | ||
67 | struct hifier_data *data = chip->model_data; | ||
68 | |||
69 | data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
70 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
71 | ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); | ||
72 | ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); | ||
73 | ak4396_write(chip, AK4396_LCH_ATT, 0xff); | ||
74 | ak4396_write(chip, AK4396_RCH_ATT, 0xff); | ||
75 | |||
76 | snd_component_add(chip->card, "AK4396"); | ||
77 | snd_component_add(chip->card, "CS5340"); | ||
78 | } | ||
79 | |||
80 | static void hifier_cleanup(struct oxygen *chip) | ||
81 | { | ||
82 | } | ||
83 | |||
84 | static void set_ak4396_params(struct oxygen *chip, | ||
85 | struct snd_pcm_hw_params *params) | ||
86 | { | ||
87 | struct hifier_data *data = chip->model_data; | ||
88 | u8 value; | ||
89 | |||
90 | value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; | ||
91 | if (params_rate(params) <= 54000) | ||
92 | value |= AK4396_DFS_NORMAL; | ||
93 | else if (params_rate(params) <= 108000) | ||
94 | value |= AK4396_DFS_DOUBLE; | ||
95 | else | ||
96 | value |= AK4396_DFS_QUAD; | ||
97 | data->ak4396_ctl2 = value; | ||
98 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); | ||
99 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
100 | ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
101 | } | ||
102 | |||
103 | static void update_ak4396_volume(struct oxygen *chip) | ||
104 | { | ||
105 | ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); | ||
106 | ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); | ||
107 | } | ||
108 | |||
109 | static void update_ak4396_mute(struct oxygen *chip) | ||
110 | { | ||
111 | struct hifier_data *data = chip->model_data; | ||
112 | u8 value; | ||
113 | |||
114 | value = data->ak4396_ctl2 & ~AK4396_SMUTE; | ||
115 | if (chip->dac_mute) | ||
116 | value |= AK4396_SMUTE; | ||
117 | data->ak4396_ctl2 = value; | ||
118 | ak4396_write(chip, AK4396_CONTROL_2, value); | ||
119 | } | ||
120 | |||
121 | static void set_cs5340_params(struct oxygen *chip, | ||
122 | struct snd_pcm_hw_params *params) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
127 | |||
128 | static int hifier_control_filter(struct snd_kcontrol_new *template) | ||
129 | { | ||
130 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
131 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
132 | template->tlv.p = ak4396_db_scale; | ||
133 | } else if (!strcmp(template->name, "Stereo Upmixing")) { | ||
134 | return 1; /* stereo only - we don't need upmixing */ | ||
135 | } else if (!strcmp(template->name, | ||
136 | SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK)) || | ||
137 | !strcmp(template->name, | ||
138 | SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT))) { | ||
139 | return 1; /* no digital input */ | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int hifier_mixer_init(struct oxygen *chip) | ||
145 | { | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static const struct oxygen_model model_hifier = { | ||
150 | .shortname = "C-Media CMI8787", | ||
151 | .longname = "C-Media Oxygen HD Audio", | ||
152 | .chip = "CMI8788", | ||
153 | .init = hifier_init, | ||
154 | .control_filter = hifier_control_filter, | ||
155 | .mixer_init = hifier_mixer_init, | ||
156 | .cleanup = hifier_cleanup, | ||
157 | .set_dac_params = set_ak4396_params, | ||
158 | .set_adc_params = set_cs5340_params, | ||
159 | .update_dac_volume = update_ak4396_volume, | ||
160 | .update_dac_mute = update_ak4396_mute, | ||
161 | .model_data_size = sizeof(struct hifier_data), | ||
162 | .dac_channels = 2, | ||
163 | .used_channels = OXYGEN_CHANNEL_A | | ||
164 | OXYGEN_CHANNEL_SPDIF | | ||
165 | OXYGEN_CHANNEL_MULTICH, | ||
166 | .function_flags = 0, | ||
167 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
168 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
169 | }; | ||
170 | |||
171 | static int __devinit hifier_probe(struct pci_dev *pci, | ||
172 | const struct pci_device_id *pci_id) | ||
173 | { | ||
174 | static int dev; | ||
175 | int err; | ||
176 | |||
177 | if (dev >= SNDRV_CARDS) | ||
178 | return -ENODEV; | ||
179 | if (!enable[dev]) { | ||
180 | ++dev; | ||
181 | return -ENOENT; | ||
182 | } | ||
183 | err = oxygen_pci_probe(pci, index[dev], id[dev], 0, &model_hifier); | ||
184 | if (err >= 0) | ||
185 | ++dev; | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | static struct pci_driver hifier_driver = { | ||
190 | .name = "CMI8787HiFier", | ||
191 | .id_table = hifier_ids, | ||
192 | .probe = hifier_probe, | ||
193 | .remove = __devexit_p(oxygen_pci_remove), | ||
194 | }; | ||
195 | |||
196 | static int __init alsa_card_hifier_init(void) | ||
197 | { | ||
198 | return pci_register_driver(&hifier_driver); | ||
199 | } | ||
200 | |||
201 | static void __exit alsa_card_hifier_exit(void) | ||
202 | { | ||
203 | pci_unregister_driver(&hifier_driver); | ||
204 | } | ||
205 | |||
206 | module_init(alsa_card_hifier_init) | ||
207 | module_exit(alsa_card_hifier_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c new file mode 100644 index 000000000000..f31a0eb409b0 --- /dev/null +++ b/sound/pci/oxygen/oxygen.c | |||
@@ -0,0 +1,385 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for C-Media's reference design and for the X-Meridian | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * SPI 0 -> 1st AK4396 (front) | ||
22 | * SPI 1 -> 2nd AK4396 (surround) | ||
23 | * SPI 2 -> 3rd AK4396 (center/LFE) | ||
24 | * SPI 3 -> WM8785 | ||
25 | * SPI 4 -> 4th AK4396 (back) | ||
26 | * | ||
27 | * GPIO 0 -> DFS0 of AK5385 | ||
28 | * GPIO 1 -> DFS1 of AK5385 | ||
29 | */ | ||
30 | |||
31 | #include <linux/pci.h> | ||
32 | #include <sound/control.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/initval.h> | ||
35 | #include <sound/pcm.h> | ||
36 | #include <sound/pcm_params.h> | ||
37 | #include <sound/tlv.h> | ||
38 | #include "oxygen.h" | ||
39 | #include "ak4396.h" | ||
40 | |||
41 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
42 | MODULE_DESCRIPTION("C-Media CMI8788 driver"); | ||
43 | MODULE_LICENSE("GPL"); | ||
44 | MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8788}}"); | ||
45 | |||
46 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
47 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
48 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
49 | |||
50 | module_param_array(index, int, NULL, 0444); | ||
51 | MODULE_PARM_DESC(index, "card index"); | ||
52 | module_param_array(id, charp, NULL, 0444); | ||
53 | MODULE_PARM_DESC(id, "ID string"); | ||
54 | module_param_array(enable, bool, NULL, 0444); | ||
55 | MODULE_PARM_DESC(enable, "enable card"); | ||
56 | |||
57 | static struct pci_device_id oxygen_ids[] __devinitdata = { | ||
58 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216) }, | ||
59 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218) }, | ||
60 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219) }, | ||
61 | { OXYGEN_PCI_SUBID(0x13f6, 0x0001) }, | ||
62 | { OXYGEN_PCI_SUBID(0x13f6, 0x0010) }, | ||
63 | { OXYGEN_PCI_SUBID(0x13f6, 0x8788) }, | ||
64 | { OXYGEN_PCI_SUBID(0x147a, 0xa017) }, | ||
65 | { OXYGEN_PCI_SUBID(0x1a58, 0x0910) }, | ||
66 | { OXYGEN_PCI_SUBID(0x415a, 0x5431), .driver_data = 1 }, | ||
67 | { OXYGEN_PCI_SUBID(0x7284, 0x9761) }, | ||
68 | { } | ||
69 | }; | ||
70 | MODULE_DEVICE_TABLE(pci, oxygen_ids); | ||
71 | |||
72 | |||
73 | #define GPIO_AK5385_DFS_MASK 0x0003 | ||
74 | #define GPIO_AK5385_DFS_NORMAL 0x0000 | ||
75 | #define GPIO_AK5385_DFS_DOUBLE 0x0001 | ||
76 | #define GPIO_AK5385_DFS_QUAD 0x0002 | ||
77 | |||
78 | #define WM8785_R0 0 | ||
79 | #define WM8785_R1 1 | ||
80 | #define WM8785_R2 2 | ||
81 | #define WM8785_R7 7 | ||
82 | |||
83 | /* R0 */ | ||
84 | #define WM8785_MCR_MASK 0x007 | ||
85 | #define WM8785_MCR_SLAVE 0x000 | ||
86 | #define WM8785_MCR_MASTER_128 0x001 | ||
87 | #define WM8785_MCR_MASTER_192 0x002 | ||
88 | #define WM8785_MCR_MASTER_256 0x003 | ||
89 | #define WM8785_MCR_MASTER_384 0x004 | ||
90 | #define WM8785_MCR_MASTER_512 0x005 | ||
91 | #define WM8785_MCR_MASTER_768 0x006 | ||
92 | #define WM8785_OSR_MASK 0x018 | ||
93 | #define WM8785_OSR_SINGLE 0x000 | ||
94 | #define WM8785_OSR_DOUBLE 0x008 | ||
95 | #define WM8785_OSR_QUAD 0x010 | ||
96 | #define WM8785_FORMAT_MASK 0x060 | ||
97 | #define WM8785_FORMAT_RJUST 0x000 | ||
98 | #define WM8785_FORMAT_LJUST 0x020 | ||
99 | #define WM8785_FORMAT_I2S 0x040 | ||
100 | #define WM8785_FORMAT_DSP 0x060 | ||
101 | /* R1 */ | ||
102 | #define WM8785_WL_MASK 0x003 | ||
103 | #define WM8785_WL_16 0x000 | ||
104 | #define WM8785_WL_20 0x001 | ||
105 | #define WM8785_WL_24 0x002 | ||
106 | #define WM8785_WL_32 0x003 | ||
107 | #define WM8785_LRP 0x004 | ||
108 | #define WM8785_BCLKINV 0x008 | ||
109 | #define WM8785_LRSWAP 0x010 | ||
110 | #define WM8785_DEVNO_MASK 0x0e0 | ||
111 | /* R2 */ | ||
112 | #define WM8785_HPFR 0x001 | ||
113 | #define WM8785_HPFL 0x002 | ||
114 | #define WM8785_SDODIS 0x004 | ||
115 | #define WM8785_PWRDNR 0x008 | ||
116 | #define WM8785_PWRDNL 0x010 | ||
117 | #define WM8785_TDM_MASK 0x1c0 | ||
118 | |||
119 | struct generic_data { | ||
120 | u8 ak4396_ctl2; | ||
121 | }; | ||
122 | |||
123 | static void ak4396_write(struct oxygen *chip, unsigned int codec, | ||
124 | u8 reg, u8 value) | ||
125 | { | ||
126 | /* maps ALSA channel pair number to SPI output */ | ||
127 | static const u8 codec_spi_map[4] = { | ||
128 | 0, 1, 2, 4 | ||
129 | }; | ||
130 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
131 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
132 | OXYGEN_SPI_CLOCK_160 | | ||
133 | (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | | ||
134 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
135 | AK4396_WRITE | (reg << 8) | value); | ||
136 | } | ||
137 | |||
138 | static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) | ||
139 | { | ||
140 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
141 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
142 | OXYGEN_SPI_CLOCK_160 | | ||
143 | (3 << OXYGEN_SPI_CODEC_SHIFT) | | ||
144 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
145 | (reg << 9) | value); | ||
146 | } | ||
147 | |||
148 | static void ak4396_init(struct oxygen *chip) | ||
149 | { | ||
150 | struct generic_data *data = chip->model_data; | ||
151 | unsigned int i; | ||
152 | |||
153 | data->ak4396_ctl2 = AK4396_DEM_OFF | AK4396_DFS_NORMAL; | ||
154 | for (i = 0; i < 4; ++i) { | ||
155 | ak4396_write(chip, i, | ||
156 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
157 | ak4396_write(chip, i, | ||
158 | AK4396_CONTROL_2, data->ak4396_ctl2); | ||
159 | ak4396_write(chip, i, | ||
160 | AK4396_CONTROL_3, AK4396_PCM); | ||
161 | ak4396_write(chip, i, AK4396_LCH_ATT, 0xff); | ||
162 | ak4396_write(chip, i, AK4396_RCH_ATT, 0xff); | ||
163 | } | ||
164 | snd_component_add(chip->card, "AK4396"); | ||
165 | } | ||
166 | |||
167 | static void ak5385_init(struct oxygen *chip) | ||
168 | { | ||
169 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_AK5385_DFS_MASK); | ||
170 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_AK5385_DFS_MASK); | ||
171 | snd_component_add(chip->card, "AK5385"); | ||
172 | } | ||
173 | |||
174 | static void wm8785_init(struct oxygen *chip) | ||
175 | { | ||
176 | wm8785_write(chip, WM8785_R7, 0); | ||
177 | wm8785_write(chip, WM8785_R0, WM8785_MCR_SLAVE | | ||
178 | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST); | ||
179 | wm8785_write(chip, WM8785_R1, WM8785_WL_24); | ||
180 | snd_component_add(chip->card, "WM8785"); | ||
181 | } | ||
182 | |||
183 | static void generic_init(struct oxygen *chip) | ||
184 | { | ||
185 | ak4396_init(chip); | ||
186 | wm8785_init(chip); | ||
187 | } | ||
188 | |||
189 | static void meridian_init(struct oxygen *chip) | ||
190 | { | ||
191 | ak4396_init(chip); | ||
192 | ak5385_init(chip); | ||
193 | } | ||
194 | |||
195 | static void generic_cleanup(struct oxygen *chip) | ||
196 | { | ||
197 | } | ||
198 | |||
199 | static void set_ak4396_params(struct oxygen *chip, | ||
200 | struct snd_pcm_hw_params *params) | ||
201 | { | ||
202 | struct generic_data *data = chip->model_data; | ||
203 | unsigned int i; | ||
204 | u8 value; | ||
205 | |||
206 | value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; | ||
207 | if (params_rate(params) <= 54000) | ||
208 | value |= AK4396_DFS_NORMAL; | ||
209 | else if (params_rate(params) <= 108000) | ||
210 | value |= AK4396_DFS_DOUBLE; | ||
211 | else | ||
212 | value |= AK4396_DFS_QUAD; | ||
213 | data->ak4396_ctl2 = value; | ||
214 | for (i = 0; i < 4; ++i) { | ||
215 | ak4396_write(chip, i, | ||
216 | AK4396_CONTROL_1, AK4396_DIF_24_MSB); | ||
217 | ak4396_write(chip, i, | ||
218 | AK4396_CONTROL_2, value); | ||
219 | ak4396_write(chip, i, | ||
220 | AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static void update_ak4396_volume(struct oxygen *chip) | ||
225 | { | ||
226 | unsigned int i; | ||
227 | |||
228 | for (i = 0; i < 4; ++i) { | ||
229 | ak4396_write(chip, i, | ||
230 | AK4396_LCH_ATT, chip->dac_volume[i * 2]); | ||
231 | ak4396_write(chip, i, | ||
232 | AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static void update_ak4396_mute(struct oxygen *chip) | ||
237 | { | ||
238 | struct generic_data *data = chip->model_data; | ||
239 | unsigned int i; | ||
240 | u8 value; | ||
241 | |||
242 | value = data->ak4396_ctl2 & ~AK4396_SMUTE; | ||
243 | if (chip->dac_mute) | ||
244 | value |= AK4396_SMUTE; | ||
245 | data->ak4396_ctl2 = value; | ||
246 | for (i = 0; i < 4; ++i) | ||
247 | ak4396_write(chip, i, AK4396_CONTROL_2, value); | ||
248 | } | ||
249 | |||
250 | static void set_wm8785_params(struct oxygen *chip, | ||
251 | struct snd_pcm_hw_params *params) | ||
252 | { | ||
253 | unsigned int value; | ||
254 | |||
255 | wm8785_write(chip, WM8785_R7, 0); | ||
256 | |||
257 | value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST; | ||
258 | if (params_rate(params) <= 48000) | ||
259 | value |= WM8785_OSR_SINGLE; | ||
260 | else if (params_rate(params) <= 96000) | ||
261 | value |= WM8785_OSR_DOUBLE; | ||
262 | else | ||
263 | value |= WM8785_OSR_QUAD; | ||
264 | wm8785_write(chip, WM8785_R0, value); | ||
265 | |||
266 | if (snd_pcm_format_width(params_format(params)) <= 16) | ||
267 | value = WM8785_WL_16; | ||
268 | else | ||
269 | value = WM8785_WL_24; | ||
270 | wm8785_write(chip, WM8785_R1, value); | ||
271 | } | ||
272 | |||
273 | static void set_ak5385_params(struct oxygen *chip, | ||
274 | struct snd_pcm_hw_params *params) | ||
275 | { | ||
276 | unsigned int value; | ||
277 | |||
278 | if (params_rate(params) <= 54000) | ||
279 | value = GPIO_AK5385_DFS_NORMAL; | ||
280 | else if (params_rate(params) <= 108000) | ||
281 | value = GPIO_AK5385_DFS_DOUBLE; | ||
282 | else | ||
283 | value = GPIO_AK5385_DFS_QUAD; | ||
284 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
285 | value, GPIO_AK5385_DFS_MASK); | ||
286 | } | ||
287 | |||
288 | static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); | ||
289 | |||
290 | static int ak4396_control_filter(struct snd_kcontrol_new *template) | ||
291 | { | ||
292 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
293 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
294 | template->tlv.p = ak4396_db_scale; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static const struct oxygen_model model_generic = { | ||
300 | .shortname = "C-Media CMI8788", | ||
301 | .longname = "C-Media Oxygen HD Audio", | ||
302 | .chip = "CMI8788", | ||
303 | .owner = THIS_MODULE, | ||
304 | .init = generic_init, | ||
305 | .control_filter = ak4396_control_filter, | ||
306 | .cleanup = generic_cleanup, | ||
307 | .set_dac_params = set_ak4396_params, | ||
308 | .set_adc_params = set_wm8785_params, | ||
309 | .update_dac_volume = update_ak4396_volume, | ||
310 | .update_dac_mute = update_ak4396_mute, | ||
311 | .model_data_size = sizeof(struct generic_data), | ||
312 | .dac_channels = 8, | ||
313 | .used_channels = OXYGEN_CHANNEL_A | | ||
314 | OXYGEN_CHANNEL_C | | ||
315 | OXYGEN_CHANNEL_SPDIF | | ||
316 | OXYGEN_CHANNEL_MULTICH | | ||
317 | OXYGEN_CHANNEL_AC97, | ||
318 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
319 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
320 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
321 | }; | ||
322 | static const struct oxygen_model model_meridian = { | ||
323 | .shortname = "C-Media CMI8788", | ||
324 | .longname = "C-Media Oxygen HD Audio", | ||
325 | .chip = "CMI8788", | ||
326 | .owner = THIS_MODULE, | ||
327 | .init = meridian_init, | ||
328 | .control_filter = ak4396_control_filter, | ||
329 | .cleanup = generic_cleanup, | ||
330 | .set_dac_params = set_ak4396_params, | ||
331 | .set_adc_params = set_ak5385_params, | ||
332 | .update_dac_volume = update_ak4396_volume, | ||
333 | .update_dac_mute = update_ak4396_mute, | ||
334 | .model_data_size = sizeof(struct generic_data), | ||
335 | .dac_channels = 8, | ||
336 | .used_channels = OXYGEN_CHANNEL_B | | ||
337 | OXYGEN_CHANNEL_C | | ||
338 | OXYGEN_CHANNEL_SPDIF | | ||
339 | OXYGEN_CHANNEL_MULTICH | | ||
340 | OXYGEN_CHANNEL_AC97, | ||
341 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
342 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
343 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
344 | }; | ||
345 | |||
346 | static int __devinit generic_oxygen_probe(struct pci_dev *pci, | ||
347 | const struct pci_device_id *pci_id) | ||
348 | { | ||
349 | static int dev; | ||
350 | int is_meridian; | ||
351 | int err; | ||
352 | |||
353 | if (dev >= SNDRV_CARDS) | ||
354 | return -ENODEV; | ||
355 | if (!enable[dev]) { | ||
356 | ++dev; | ||
357 | return -ENOENT; | ||
358 | } | ||
359 | is_meridian = pci_id->driver_data; | ||
360 | err = oxygen_pci_probe(pci, index[dev], id[dev], is_meridian, | ||
361 | is_meridian ? &model_meridian : &model_generic); | ||
362 | if (err >= 0) | ||
363 | ++dev; | ||
364 | return err; | ||
365 | } | ||
366 | |||
367 | static struct pci_driver oxygen_driver = { | ||
368 | .name = "CMI8788", | ||
369 | .id_table = oxygen_ids, | ||
370 | .probe = generic_oxygen_probe, | ||
371 | .remove = __devexit_p(oxygen_pci_remove), | ||
372 | }; | ||
373 | |||
374 | static int __init alsa_card_oxygen_init(void) | ||
375 | { | ||
376 | return pci_register_driver(&oxygen_driver); | ||
377 | } | ||
378 | |||
379 | static void __exit alsa_card_oxygen_exit(void) | ||
380 | { | ||
381 | pci_unregister_driver(&oxygen_driver); | ||
382 | } | ||
383 | |||
384 | module_init(alsa_card_oxygen_init) | ||
385 | module_exit(alsa_card_oxygen_exit) | ||
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h new file mode 100644 index 000000000000..ad50fb8b206b --- /dev/null +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -0,0 +1,190 @@ | |||
1 | #ifndef OXYGEN_H_INCLUDED | ||
2 | #define OXYGEN_H_INCLUDED | ||
3 | |||
4 | #include <linux/mutex.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include <linux/wait.h> | ||
7 | #include <linux/workqueue.h> | ||
8 | #include "oxygen_regs.h" | ||
9 | |||
10 | /* 1 << PCM_x == OXYGEN_CHANNEL_x */ | ||
11 | #define PCM_A 0 | ||
12 | #define PCM_B 1 | ||
13 | #define PCM_C 2 | ||
14 | #define PCM_SPDIF 3 | ||
15 | #define PCM_MULTICH 4 | ||
16 | #define PCM_AC97 5 | ||
17 | #define PCM_COUNT 6 | ||
18 | |||
19 | enum { | ||
20 | CONTROL_SPDIF_PCM, | ||
21 | CONTROL_SPDIF_INPUT_BITS, | ||
22 | CONTROL_MIC_CAPTURE_SWITCH, | ||
23 | CONTROL_LINE_CAPTURE_SWITCH, | ||
24 | CONTROL_CD_CAPTURE_SWITCH, | ||
25 | CONTROL_AUX_CAPTURE_SWITCH, | ||
26 | CONTROL_COUNT | ||
27 | }; | ||
28 | |||
29 | #define OXYGEN_PCI_SUBID(sv, sd) \ | ||
30 | .vendor = PCI_VENDOR_ID_CMEDIA, \ | ||
31 | .device = 0x8788, \ | ||
32 | .subvendor = sv, \ | ||
33 | .subdevice = sd | ||
34 | |||
35 | struct pci_dev; | ||
36 | struct snd_card; | ||
37 | struct snd_pcm_substream; | ||
38 | struct snd_pcm_hardware; | ||
39 | struct snd_pcm_hw_params; | ||
40 | struct snd_kcontrol_new; | ||
41 | struct snd_rawmidi; | ||
42 | struct oxygen_model; | ||
43 | |||
44 | struct oxygen { | ||
45 | unsigned long addr; | ||
46 | spinlock_t reg_lock; | ||
47 | struct mutex mutex; | ||
48 | struct snd_card *card; | ||
49 | struct pci_dev *pci; | ||
50 | struct snd_rawmidi *midi; | ||
51 | int irq; | ||
52 | const struct oxygen_model *model; | ||
53 | void *model_data; | ||
54 | unsigned int interrupt_mask; | ||
55 | u8 dac_volume[8]; | ||
56 | u8 dac_mute; | ||
57 | u8 pcm_active; | ||
58 | u8 pcm_running; | ||
59 | u8 dac_routing; | ||
60 | u8 spdif_playback_enable; | ||
61 | u8 revision; | ||
62 | u8 has_ac97_0; | ||
63 | u8 has_ac97_1; | ||
64 | u32 spdif_bits; | ||
65 | u32 spdif_pcm_bits; | ||
66 | struct snd_pcm_substream *streams[PCM_COUNT]; | ||
67 | struct snd_kcontrol *controls[CONTROL_COUNT]; | ||
68 | struct work_struct spdif_input_bits_work; | ||
69 | struct work_struct gpio_work; | ||
70 | wait_queue_head_t ac97_waitqueue; | ||
71 | }; | ||
72 | |||
73 | struct oxygen_model { | ||
74 | const char *shortname; | ||
75 | const char *longname; | ||
76 | const char *chip; | ||
77 | struct module *owner; | ||
78 | void (*init)(struct oxygen *chip); | ||
79 | int (*control_filter)(struct snd_kcontrol_new *template); | ||
80 | int (*mixer_init)(struct oxygen *chip); | ||
81 | void (*cleanup)(struct oxygen *chip); | ||
82 | void (*pcm_hardware_filter)(unsigned int channel, | ||
83 | struct snd_pcm_hardware *hardware); | ||
84 | void (*set_dac_params)(struct oxygen *chip, | ||
85 | struct snd_pcm_hw_params *params); | ||
86 | void (*set_adc_params)(struct oxygen *chip, | ||
87 | struct snd_pcm_hw_params *params); | ||
88 | void (*update_dac_volume)(struct oxygen *chip); | ||
89 | void (*update_dac_mute)(struct oxygen *chip); | ||
90 | void (*ac97_switch_hook)(struct oxygen *chip, unsigned int codec, | ||
91 | unsigned int reg, int mute); | ||
92 | void (*gpio_changed)(struct oxygen *chip); | ||
93 | size_t model_data_size; | ||
94 | u8 dac_channels; | ||
95 | u8 used_channels; | ||
96 | u8 function_flags; | ||
97 | u16 dac_i2s_format; | ||
98 | u16 adc_i2s_format; | ||
99 | }; | ||
100 | |||
101 | /* oxygen_lib.c */ | ||
102 | |||
103 | int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, int midi, | ||
104 | const struct oxygen_model *model); | ||
105 | void oxygen_pci_remove(struct pci_dev *pci); | ||
106 | |||
107 | /* oxygen_mixer.c */ | ||
108 | |||
109 | int oxygen_mixer_init(struct oxygen *chip); | ||
110 | void oxygen_update_dac_routing(struct oxygen *chip); | ||
111 | void oxygen_update_spdif_source(struct oxygen *chip); | ||
112 | |||
113 | /* oxygen_pcm.c */ | ||
114 | |||
115 | int oxygen_pcm_init(struct oxygen *chip); | ||
116 | |||
117 | /* oxygen_io.c */ | ||
118 | |||
119 | u8 oxygen_read8(struct oxygen *chip, unsigned int reg); | ||
120 | u16 oxygen_read16(struct oxygen *chip, unsigned int reg); | ||
121 | u32 oxygen_read32(struct oxygen *chip, unsigned int reg); | ||
122 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value); | ||
123 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value); | ||
124 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value); | ||
125 | void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | ||
126 | u8 value, u8 mask); | ||
127 | void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | ||
128 | u16 value, u16 mask); | ||
129 | void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | ||
130 | u32 value, u32 mask); | ||
131 | |||
132 | u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, | ||
133 | unsigned int index); | ||
134 | void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | ||
135 | unsigned int index, u16 data); | ||
136 | void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, | ||
137 | unsigned int index, u16 data, u16 mask); | ||
138 | |||
139 | void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); | ||
140 | |||
141 | static inline void oxygen_set_bits8(struct oxygen *chip, | ||
142 | unsigned int reg, u8 value) | ||
143 | { | ||
144 | oxygen_write8_masked(chip, reg, value, value); | ||
145 | } | ||
146 | |||
147 | static inline void oxygen_set_bits16(struct oxygen *chip, | ||
148 | unsigned int reg, u16 value) | ||
149 | { | ||
150 | oxygen_write16_masked(chip, reg, value, value); | ||
151 | } | ||
152 | |||
153 | static inline void oxygen_set_bits32(struct oxygen *chip, | ||
154 | unsigned int reg, u32 value) | ||
155 | { | ||
156 | oxygen_write32_masked(chip, reg, value, value); | ||
157 | } | ||
158 | |||
159 | static inline void oxygen_clear_bits8(struct oxygen *chip, | ||
160 | unsigned int reg, u8 value) | ||
161 | { | ||
162 | oxygen_write8_masked(chip, reg, 0, value); | ||
163 | } | ||
164 | |||
165 | static inline void oxygen_clear_bits16(struct oxygen *chip, | ||
166 | unsigned int reg, u16 value) | ||
167 | { | ||
168 | oxygen_write16_masked(chip, reg, 0, value); | ||
169 | } | ||
170 | |||
171 | static inline void oxygen_clear_bits32(struct oxygen *chip, | ||
172 | unsigned int reg, u32 value) | ||
173 | { | ||
174 | oxygen_write32_masked(chip, reg, 0, value); | ||
175 | } | ||
176 | |||
177 | static inline void oxygen_ac97_set_bits(struct oxygen *chip, unsigned int codec, | ||
178 | unsigned int index, u16 value) | ||
179 | { | ||
180 | oxygen_write_ac97_masked(chip, codec, index, value, value); | ||
181 | } | ||
182 | |||
183 | static inline void oxygen_ac97_clear_bits(struct oxygen *chip, | ||
184 | unsigned int codec, | ||
185 | unsigned int index, u16 value) | ||
186 | { | ||
187 | oxygen_write_ac97_masked(chip, codec, index, 0, value); | ||
188 | } | ||
189 | |||
190 | #endif | ||
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c new file mode 100644 index 000000000000..74e23ef9c946 --- /dev/null +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - helper functions | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <asm/io.h> | ||
24 | #include "oxygen.h" | ||
25 | |||
26 | u8 oxygen_read8(struct oxygen *chip, unsigned int reg) | ||
27 | { | ||
28 | return inb(chip->addr + reg); | ||
29 | } | ||
30 | EXPORT_SYMBOL(oxygen_read8); | ||
31 | |||
32 | u16 oxygen_read16(struct oxygen *chip, unsigned int reg) | ||
33 | { | ||
34 | return inw(chip->addr + reg); | ||
35 | } | ||
36 | EXPORT_SYMBOL(oxygen_read16); | ||
37 | |||
38 | u32 oxygen_read32(struct oxygen *chip, unsigned int reg) | ||
39 | { | ||
40 | return inl(chip->addr + reg); | ||
41 | } | ||
42 | EXPORT_SYMBOL(oxygen_read32); | ||
43 | |||
44 | void oxygen_write8(struct oxygen *chip, unsigned int reg, u8 value) | ||
45 | { | ||
46 | outb(value, chip->addr + reg); | ||
47 | } | ||
48 | EXPORT_SYMBOL(oxygen_write8); | ||
49 | |||
50 | void oxygen_write16(struct oxygen *chip, unsigned int reg, u16 value) | ||
51 | { | ||
52 | outw(value, chip->addr + reg); | ||
53 | } | ||
54 | EXPORT_SYMBOL(oxygen_write16); | ||
55 | |||
56 | void oxygen_write32(struct oxygen *chip, unsigned int reg, u32 value) | ||
57 | { | ||
58 | outl(value, chip->addr + reg); | ||
59 | } | ||
60 | EXPORT_SYMBOL(oxygen_write32); | ||
61 | |||
62 | void oxygen_write8_masked(struct oxygen *chip, unsigned int reg, | ||
63 | u8 value, u8 mask) | ||
64 | { | ||
65 | u8 tmp = inb(chip->addr + reg); | ||
66 | outb((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
67 | } | ||
68 | EXPORT_SYMBOL(oxygen_write8_masked); | ||
69 | |||
70 | void oxygen_write16_masked(struct oxygen *chip, unsigned int reg, | ||
71 | u16 value, u16 mask) | ||
72 | { | ||
73 | u16 tmp = inw(chip->addr + reg); | ||
74 | outw((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
75 | } | ||
76 | EXPORT_SYMBOL(oxygen_write16_masked); | ||
77 | |||
78 | void oxygen_write32_masked(struct oxygen *chip, unsigned int reg, | ||
79 | u32 value, u32 mask) | ||
80 | { | ||
81 | u32 tmp = inl(chip->addr + reg); | ||
82 | outl((tmp & ~mask) | (value & mask), chip->addr + reg); | ||
83 | } | ||
84 | EXPORT_SYMBOL(oxygen_write32_masked); | ||
85 | |||
86 | static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask) | ||
87 | { | ||
88 | u8 status = 0; | ||
89 | |||
90 | /* | ||
91 | * Reading the status register also clears the bits, so we have to save | ||
92 | * the read bits in status. | ||
93 | */ | ||
94 | wait_event_timeout(chip->ac97_waitqueue, | ||
95 | ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); | ||
96 | status & mask; }), | ||
97 | msecs_to_jiffies(1) + 1); | ||
98 | /* | ||
99 | * Check even after a timeout because this function should not require | ||
100 | * the AC'97 interrupt to be enabled. | ||
101 | */ | ||
102 | status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); | ||
103 | return status & mask ? 0 : -EIO; | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * About 10% of AC'97 register reads or writes fail to complete, but even those | ||
108 | * where the controller indicates completion aren't guaranteed to have actually | ||
109 | * happened. | ||
110 | * | ||
111 | * It's hard to assign blame to either the controller or the codec because both | ||
112 | * were made by C-Media ... | ||
113 | */ | ||
114 | |||
115 | void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, | ||
116 | unsigned int index, u16 data) | ||
117 | { | ||
118 | unsigned int count, succeeded; | ||
119 | u32 reg; | ||
120 | |||
121 | reg = data; | ||
122 | reg |= index << OXYGEN_AC97_REG_ADDR_SHIFT; | ||
123 | reg |= OXYGEN_AC97_REG_DIR_WRITE; | ||
124 | reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; | ||
125 | succeeded = 0; | ||
126 | for (count = 5; count > 0; --count) { | ||
127 | udelay(5); | ||
128 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | ||
129 | /* require two "completed" writes, just to be sure */ | ||
130 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_WRITE_DONE) >= 0 && | ||
131 | ++succeeded >= 2) | ||
132 | return; | ||
133 | } | ||
134 | snd_printk(KERN_ERR "AC'97 write timeout\n"); | ||
135 | } | ||
136 | EXPORT_SYMBOL(oxygen_write_ac97); | ||
137 | |||
138 | u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, | ||
139 | unsigned int index) | ||
140 | { | ||
141 | unsigned int count; | ||
142 | unsigned int last_read = UINT_MAX; | ||
143 | u32 reg; | ||
144 | |||
145 | reg = index << OXYGEN_AC97_REG_ADDR_SHIFT; | ||
146 | reg |= OXYGEN_AC97_REG_DIR_READ; | ||
147 | reg |= codec << OXYGEN_AC97_REG_CODEC_SHIFT; | ||
148 | for (count = 5; count > 0; --count) { | ||
149 | udelay(5); | ||
150 | oxygen_write32(chip, OXYGEN_AC97_REGS, reg); | ||
151 | udelay(10); | ||
152 | if (oxygen_ac97_wait(chip, OXYGEN_AC97_INT_READ_DONE) >= 0) { | ||
153 | u16 value = oxygen_read16(chip, OXYGEN_AC97_REGS); | ||
154 | /* we require two consecutive reads of the same value */ | ||
155 | if (value == last_read) | ||
156 | return value; | ||
157 | last_read = value; | ||
158 | /* | ||
159 | * Invert the register value bits to make sure that two | ||
160 | * consecutive unsuccessful reads do not return the same | ||
161 | * value. | ||
162 | */ | ||
163 | reg ^= 0xffff; | ||
164 | } | ||
165 | } | ||
166 | snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec); | ||
167 | return 0; | ||
168 | } | ||
169 | EXPORT_SYMBOL(oxygen_read_ac97); | ||
170 | |||
171 | void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, | ||
172 | unsigned int index, u16 data, u16 mask) | ||
173 | { | ||
174 | u16 value = oxygen_read_ac97(chip, codec, index); | ||
175 | value &= ~mask; | ||
176 | value |= data & mask; | ||
177 | oxygen_write_ac97(chip, codec, index, value); | ||
178 | } | ||
179 | EXPORT_SYMBOL(oxygen_write_ac97_masked); | ||
180 | |||
181 | void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) | ||
182 | { | ||
183 | unsigned int count; | ||
184 | |||
185 | /* should not need more than 7.68 us (24 * 320 ns) */ | ||
186 | count = 10; | ||
187 | while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) | ||
188 | && count > 0) { | ||
189 | udelay(1); | ||
190 | --count; | ||
191 | } | ||
192 | |||
193 | spin_lock_irq(&chip->reg_lock); | ||
194 | oxygen_write8(chip, OXYGEN_SPI_DATA1, data); | ||
195 | oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); | ||
196 | if (control & OXYGEN_SPI_DATA_LENGTH_3) | ||
197 | oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); | ||
198 | oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); | ||
199 | spin_unlock_irq(&chip->reg_lock); | ||
200 | } | ||
201 | EXPORT_SYMBOL(oxygen_write_spi); | ||
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c new file mode 100644 index 000000000000..6eb36dd11476 --- /dev/null +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -0,0 +1,515 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - main driver module | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <sound/ac97_codec.h> | ||
25 | #include <sound/asoundef.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/info.h> | ||
28 | #include <sound/mpu401.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include "oxygen.h" | ||
31 | #include "cm9780.h" | ||
32 | |||
33 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
34 | MODULE_DESCRIPTION("C-Media CMI8788 helper library"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | |||
38 | static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | ||
39 | { | ||
40 | struct oxygen *chip = dev_id; | ||
41 | unsigned int status, clear, elapsed_streams, i; | ||
42 | |||
43 | status = oxygen_read16(chip, OXYGEN_INTERRUPT_STATUS); | ||
44 | if (!status) | ||
45 | return IRQ_NONE; | ||
46 | |||
47 | spin_lock(&chip->reg_lock); | ||
48 | |||
49 | clear = status & (OXYGEN_CHANNEL_A | | ||
50 | OXYGEN_CHANNEL_B | | ||
51 | OXYGEN_CHANNEL_C | | ||
52 | OXYGEN_CHANNEL_SPDIF | | ||
53 | OXYGEN_CHANNEL_MULTICH | | ||
54 | OXYGEN_CHANNEL_AC97 | | ||
55 | OXYGEN_INT_SPDIF_IN_DETECT | | ||
56 | OXYGEN_INT_GPIO | | ||
57 | OXYGEN_INT_AC97); | ||
58 | if (clear) { | ||
59 | if (clear & OXYGEN_INT_SPDIF_IN_DETECT) | ||
60 | chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; | ||
61 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
62 | chip->interrupt_mask & ~clear); | ||
63 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
64 | chip->interrupt_mask); | ||
65 | } | ||
66 | |||
67 | elapsed_streams = status & chip->pcm_running; | ||
68 | |||
69 | spin_unlock(&chip->reg_lock); | ||
70 | |||
71 | for (i = 0; i < PCM_COUNT; ++i) | ||
72 | if ((elapsed_streams & (1 << i)) && chip->streams[i]) | ||
73 | snd_pcm_period_elapsed(chip->streams[i]); | ||
74 | |||
75 | if (status & OXYGEN_INT_SPDIF_IN_DETECT) { | ||
76 | spin_lock(&chip->reg_lock); | ||
77 | i = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
78 | if (i & (OXYGEN_SPDIF_SENSE_INT | OXYGEN_SPDIF_LOCK_INT | | ||
79 | OXYGEN_SPDIF_RATE_INT)) { | ||
80 | /* write the interrupt bit(s) to clear */ | ||
81 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, i); | ||
82 | schedule_work(&chip->spdif_input_bits_work); | ||
83 | } | ||
84 | spin_unlock(&chip->reg_lock); | ||
85 | } | ||
86 | |||
87 | if (status & OXYGEN_INT_GPIO) | ||
88 | schedule_work(&chip->gpio_work); | ||
89 | |||
90 | if ((status & OXYGEN_INT_MIDI) && chip->midi) | ||
91 | snd_mpu401_uart_interrupt(0, chip->midi->private_data); | ||
92 | |||
93 | if (status & OXYGEN_INT_AC97) | ||
94 | wake_up(&chip->ac97_waitqueue); | ||
95 | |||
96 | return IRQ_HANDLED; | ||
97 | } | ||
98 | |||
99 | static void oxygen_spdif_input_bits_changed(struct work_struct *work) | ||
100 | { | ||
101 | struct oxygen *chip = container_of(work, struct oxygen, | ||
102 | spdif_input_bits_work); | ||
103 | u32 reg; | ||
104 | |||
105 | /* | ||
106 | * This function gets called when there is new activity on the SPDIF | ||
107 | * input, or when we lose lock on the input signal, or when the rate | ||
108 | * changes. | ||
109 | */ | ||
110 | msleep(1); | ||
111 | spin_lock_irq(&chip->reg_lock); | ||
112 | reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
113 | if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | | ||
114 | OXYGEN_SPDIF_LOCK_STATUS)) | ||
115 | == OXYGEN_SPDIF_SENSE_STATUS) { | ||
116 | /* | ||
117 | * If we detect activity on the SPDIF input but cannot lock to | ||
118 | * a signal, the clock bit is likely to be wrong. | ||
119 | */ | ||
120 | reg ^= OXYGEN_SPDIF_IN_CLOCK_MASK; | ||
121 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); | ||
122 | spin_unlock_irq(&chip->reg_lock); | ||
123 | msleep(1); | ||
124 | spin_lock_irq(&chip->reg_lock); | ||
125 | reg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
126 | if ((reg & (OXYGEN_SPDIF_SENSE_STATUS | | ||
127 | OXYGEN_SPDIF_LOCK_STATUS)) | ||
128 | == OXYGEN_SPDIF_SENSE_STATUS) { | ||
129 | /* nothing detected with either clock; give up */ | ||
130 | if ((reg & OXYGEN_SPDIF_IN_CLOCK_MASK) | ||
131 | == OXYGEN_SPDIF_IN_CLOCK_192) { | ||
132 | /* | ||
133 | * Reset clock to <= 96 kHz because this is | ||
134 | * more likely to be received next time. | ||
135 | */ | ||
136 | reg &= ~OXYGEN_SPDIF_IN_CLOCK_MASK; | ||
137 | reg |= OXYGEN_SPDIF_IN_CLOCK_96; | ||
138 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, reg); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | spin_unlock_irq(&chip->reg_lock); | ||
143 | |||
144 | if (chip->controls[CONTROL_SPDIF_INPUT_BITS]) { | ||
145 | spin_lock_irq(&chip->reg_lock); | ||
146 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; | ||
147 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, | ||
148 | chip->interrupt_mask); | ||
149 | spin_unlock_irq(&chip->reg_lock); | ||
150 | |||
151 | /* | ||
152 | * We don't actually know that any channel status bits have | ||
153 | * changed, but let's send a notification just to be sure. | ||
154 | */ | ||
155 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
156 | &chip->controls[CONTROL_SPDIF_INPUT_BITS]->id); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static void oxygen_gpio_changed(struct work_struct *work) | ||
161 | { | ||
162 | struct oxygen *chip = container_of(work, struct oxygen, gpio_work); | ||
163 | |||
164 | if (chip->model->gpio_changed) | ||
165 | chip->model->gpio_changed(chip); | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_PROC_FS | ||
169 | static void oxygen_proc_read(struct snd_info_entry *entry, | ||
170 | struct snd_info_buffer *buffer) | ||
171 | { | ||
172 | struct oxygen *chip = entry->private_data; | ||
173 | int i, j; | ||
174 | |||
175 | snd_iprintf(buffer, "CMI8788\n\n"); | ||
176 | for (i = 0; i < 0x100; i += 0x10) { | ||
177 | snd_iprintf(buffer, "%02x:", i); | ||
178 | for (j = 0; j < 0x10; ++j) | ||
179 | snd_iprintf(buffer, " %02x", oxygen_read8(chip, i + j)); | ||
180 | snd_iprintf(buffer, "\n"); | ||
181 | } | ||
182 | if (mutex_lock_interruptible(&chip->mutex) < 0) | ||
183 | return; | ||
184 | if (chip->has_ac97_0) { | ||
185 | snd_iprintf(buffer, "\nAC97\n"); | ||
186 | for (i = 0; i < 0x80; i += 0x10) { | ||
187 | snd_iprintf(buffer, "%02x:", i); | ||
188 | for (j = 0; j < 0x10; j += 2) | ||
189 | snd_iprintf(buffer, " %04x", | ||
190 | oxygen_read_ac97(chip, 0, i + j)); | ||
191 | snd_iprintf(buffer, "\n"); | ||
192 | } | ||
193 | } | ||
194 | if (chip->has_ac97_1) { | ||
195 | snd_iprintf(buffer, "\nAC97 2\n"); | ||
196 | for (i = 0; i < 0x80; i += 0x10) { | ||
197 | snd_iprintf(buffer, "%02x:", i); | ||
198 | for (j = 0; j < 0x10; j += 2) | ||
199 | snd_iprintf(buffer, " %04x", | ||
200 | oxygen_read_ac97(chip, 1, i + j)); | ||
201 | snd_iprintf(buffer, "\n"); | ||
202 | } | ||
203 | } | ||
204 | mutex_unlock(&chip->mutex); | ||
205 | } | ||
206 | |||
207 | static void __devinit oxygen_proc_init(struct oxygen *chip) | ||
208 | { | ||
209 | struct snd_info_entry *entry; | ||
210 | |||
211 | if (!snd_card_proc_new(chip->card, "cmi8788", &entry)) | ||
212 | snd_info_set_text_ops(entry, chip, oxygen_proc_read); | ||
213 | } | ||
214 | #else | ||
215 | #define oxygen_proc_init(chip) | ||
216 | #endif | ||
217 | |||
218 | static void __devinit oxygen_init(struct oxygen *chip) | ||
219 | { | ||
220 | unsigned int i; | ||
221 | |||
222 | chip->dac_routing = 1; | ||
223 | for (i = 0; i < 8; ++i) | ||
224 | chip->dac_volume[i] = 0xff; | ||
225 | chip->spdif_playback_enable = 1; | ||
226 | chip->spdif_bits = OXYGEN_SPDIF_C | OXYGEN_SPDIF_ORIGINAL | | ||
227 | (IEC958_AES1_CON_PCM_CODER << OXYGEN_SPDIF_CATEGORY_SHIFT); | ||
228 | chip->spdif_pcm_bits = chip->spdif_bits; | ||
229 | |||
230 | if (oxygen_read8(chip, OXYGEN_REVISION) & OXYGEN_REVISION_2) | ||
231 | chip->revision = 2; | ||
232 | else | ||
233 | chip->revision = 1; | ||
234 | |||
235 | if (chip->revision == 1) | ||
236 | oxygen_set_bits8(chip, OXYGEN_MISC, | ||
237 | OXYGEN_MISC_PCI_MEM_W_1_CLOCK); | ||
238 | |||
239 | i = oxygen_read16(chip, OXYGEN_AC97_CONTROL); | ||
240 | chip->has_ac97_0 = (i & OXYGEN_AC97_CODEC_0) != 0; | ||
241 | chip->has_ac97_1 = (i & OXYGEN_AC97_CODEC_1) != 0; | ||
242 | |||
243 | oxygen_set_bits8(chip, OXYGEN_FUNCTION, | ||
244 | OXYGEN_FUNCTION_RESET_CODEC | | ||
245 | chip->model->function_flags); | ||
246 | oxygen_write8_masked(chip, OXYGEN_FUNCTION, | ||
247 | OXYGEN_FUNCTION_SPI, | ||
248 | OXYGEN_FUNCTION_2WIRE_SPI_MASK); | ||
249 | oxygen_write8(chip, OXYGEN_DMA_STATUS, 0); | ||
250 | oxygen_write8(chip, OXYGEN_DMA_PAUSE, 0); | ||
251 | oxygen_write8(chip, OXYGEN_PLAY_CHANNELS, | ||
252 | OXYGEN_PLAY_CHANNELS_2 | | ||
253 | OXYGEN_DMA_A_BURST_8 | | ||
254 | OXYGEN_DMA_MULTICH_BURST_8); | ||
255 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
256 | oxygen_write8_masked(chip, OXYGEN_MISC, 0, | ||
257 | OXYGEN_MISC_WRITE_PCI_SUBID | | ||
258 | OXYGEN_MISC_REC_C_FROM_SPDIF | | ||
259 | OXYGEN_MISC_REC_B_FROM_AC97 | | ||
260 | OXYGEN_MISC_REC_A_FROM_MULTICH); | ||
261 | oxygen_write8(chip, OXYGEN_REC_FORMAT, | ||
262 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_A_SHIFT) | | ||
263 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_B_SHIFT) | | ||
264 | (OXYGEN_FORMAT_16 << OXYGEN_REC_FORMAT_C_SHIFT)); | ||
265 | oxygen_write8(chip, OXYGEN_PLAY_FORMAT, | ||
266 | (OXYGEN_FORMAT_16 << OXYGEN_SPDIF_FORMAT_SHIFT) | | ||
267 | (OXYGEN_FORMAT_16 << OXYGEN_MULTICH_FORMAT_SHIFT)); | ||
268 | oxygen_write8(chip, OXYGEN_REC_CHANNELS, OXYGEN_REC_CHANNELS_2_2_2); | ||
269 | oxygen_write16(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
270 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
271 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
272 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
273 | oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, | ||
274 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
275 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
276 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
277 | oxygen_write16(chip, OXYGEN_I2S_B_FORMAT, | ||
278 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
279 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
280 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
281 | oxygen_write16(chip, OXYGEN_I2S_C_FORMAT, | ||
282 | OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_LJUST | | ||
283 | OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | | ||
284 | OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); | ||
285 | oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, | ||
286 | OXYGEN_SPDIF_SENSE_MASK | | ||
287 | OXYGEN_SPDIF_LOCK_MASK | | ||
288 | OXYGEN_SPDIF_RATE_MASK | | ||
289 | OXYGEN_SPDIF_LOCK_PAR | | ||
290 | OXYGEN_SPDIF_IN_CLOCK_96, | ||
291 | OXYGEN_SPDIF_OUT_ENABLE | | ||
292 | OXYGEN_SPDIF_LOOPBACK | | ||
293 | OXYGEN_SPDIF_SENSE_MASK | | ||
294 | OXYGEN_SPDIF_LOCK_MASK | | ||
295 | OXYGEN_SPDIF_RATE_MASK | | ||
296 | OXYGEN_SPDIF_SENSE_PAR | | ||
297 | OXYGEN_SPDIF_LOCK_PAR | | ||
298 | OXYGEN_SPDIF_IN_CLOCK_MASK); | ||
299 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, chip->spdif_bits); | ||
300 | oxygen_clear_bits8(chip, OXYGEN_MPU401_CONTROL, OXYGEN_MPU401_LOOPBACK); | ||
301 | oxygen_write8(chip, OXYGEN_GPI_INTERRUPT_MASK, 0); | ||
302 | oxygen_write16(chip, OXYGEN_GPIO_INTERRUPT_MASK, 0); | ||
303 | oxygen_write16(chip, OXYGEN_PLAY_ROUTING, | ||
304 | OXYGEN_PLAY_MULTICH_I2S_DAC | | ||
305 | OXYGEN_PLAY_SPDIF_SPDIF | | ||
306 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
307 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
308 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
309 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT)); | ||
310 | oxygen_write8(chip, OXYGEN_REC_ROUTING, | ||
311 | OXYGEN_REC_A_ROUTE_I2S_ADC_1 | | ||
312 | OXYGEN_REC_B_ROUTE_I2S_ADC_2 | | ||
313 | OXYGEN_REC_C_ROUTE_SPDIF); | ||
314 | oxygen_write8(chip, OXYGEN_ADC_MONITOR, 0); | ||
315 | oxygen_write8(chip, OXYGEN_A_MONITOR_ROUTING, | ||
316 | (0 << OXYGEN_A_MONITOR_ROUTE_0_SHIFT) | | ||
317 | (1 << OXYGEN_A_MONITOR_ROUTE_1_SHIFT) | | ||
318 | (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) | | ||
319 | (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT)); | ||
320 | |||
321 | oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK, | ||
322 | OXYGEN_AC97_INT_READ_DONE | | ||
323 | OXYGEN_AC97_INT_WRITE_DONE); | ||
324 | oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0); | ||
325 | oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0); | ||
326 | if (!(chip->has_ac97_0 | chip->has_ac97_1)) | ||
327 | oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL, | ||
328 | OXYGEN_AC97_CLOCK_DISABLE); | ||
329 | if (!chip->has_ac97_0) { | ||
330 | oxygen_set_bits16(chip, OXYGEN_AC97_CONTROL, | ||
331 | OXYGEN_AC97_NO_CODEC_0); | ||
332 | } else { | ||
333 | oxygen_write_ac97(chip, 0, AC97_RESET, 0); | ||
334 | msleep(1); | ||
335 | oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_SETUP, | ||
336 | CM9780_GPIO0IO | CM9780_GPIO1IO); | ||
337 | oxygen_ac97_set_bits(chip, 0, CM9780_MIXER, | ||
338 | CM9780_BSTSEL | CM9780_STRO_MIC | | ||
339 | CM9780_MIX2FR | CM9780_PCBSW); | ||
340 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, | ||
341 | CM9780_RSOE | CM9780_CBOE | | ||
342 | CM9780_SSOE | CM9780_FROE | | ||
343 | CM9780_MIC2MIC | CM9780_LI2LI); | ||
344 | oxygen_write_ac97(chip, 0, AC97_MASTER, 0x0000); | ||
345 | oxygen_write_ac97(chip, 0, AC97_PC_BEEP, 0x8000); | ||
346 | oxygen_write_ac97(chip, 0, AC97_MIC, 0x8808); | ||
347 | oxygen_write_ac97(chip, 0, AC97_LINE, 0x0808); | ||
348 | oxygen_write_ac97(chip, 0, AC97_CD, 0x8808); | ||
349 | oxygen_write_ac97(chip, 0, AC97_VIDEO, 0x8808); | ||
350 | oxygen_write_ac97(chip, 0, AC97_AUX, 0x8808); | ||
351 | oxygen_write_ac97(chip, 0, AC97_REC_GAIN, 0x8000); | ||
352 | oxygen_write_ac97(chip, 0, AC97_CENTER_LFE_MASTER, 0x8080); | ||
353 | oxygen_write_ac97(chip, 0, AC97_SURROUND_MASTER, 0x8080); | ||
354 | /* power down unused ADCs and DACs */ | ||
355 | oxygen_ac97_set_bits(chip, 0, AC97_POWERDOWN, | ||
356 | AC97_PD_PR0 | AC97_PD_PR1); | ||
357 | oxygen_ac97_set_bits(chip, 0, AC97_EXTENDED_STATUS, | ||
358 | AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK); | ||
359 | } | ||
360 | if (chip->has_ac97_1) { | ||
361 | oxygen_set_bits32(chip, OXYGEN_AC97_OUT_CONFIG, | ||
362 | OXYGEN_AC97_CODEC1_SLOT3 | | ||
363 | OXYGEN_AC97_CODEC1_SLOT4); | ||
364 | oxygen_write_ac97(chip, 1, AC97_RESET, 0); | ||
365 | msleep(1); | ||
366 | oxygen_write_ac97(chip, 1, AC97_MASTER, 0x0000); | ||
367 | oxygen_write_ac97(chip, 1, AC97_HEADPHONE, 0x8000); | ||
368 | oxygen_write_ac97(chip, 1, AC97_PC_BEEP, 0x8000); | ||
369 | oxygen_write_ac97(chip, 1, AC97_MIC, 0x8808); | ||
370 | oxygen_write_ac97(chip, 1, AC97_LINE, 0x8808); | ||
371 | oxygen_write_ac97(chip, 1, AC97_CD, 0x8808); | ||
372 | oxygen_write_ac97(chip, 1, AC97_VIDEO, 0x8808); | ||
373 | oxygen_write_ac97(chip, 1, AC97_AUX, 0x8808); | ||
374 | oxygen_write_ac97(chip, 1, AC97_PCM, 0x0808); | ||
375 | oxygen_write_ac97(chip, 1, AC97_REC_SEL, 0x0000); | ||
376 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, 0x0000); | ||
377 | oxygen_ac97_set_bits(chip, 1, 0x6a, 0x0040); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | static void oxygen_card_free(struct snd_card *card) | ||
382 | { | ||
383 | struct oxygen *chip = card->private_data; | ||
384 | |||
385 | spin_lock_irq(&chip->reg_lock); | ||
386 | chip->interrupt_mask = 0; | ||
387 | chip->pcm_running = 0; | ||
388 | oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); | ||
389 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); | ||
390 | spin_unlock_irq(&chip->reg_lock); | ||
391 | if (chip->irq >= 0) { | ||
392 | free_irq(chip->irq, chip); | ||
393 | synchronize_irq(chip->irq); | ||
394 | } | ||
395 | flush_scheduled_work(); | ||
396 | chip->model->cleanup(chip); | ||
397 | mutex_destroy(&chip->mutex); | ||
398 | pci_release_regions(chip->pci); | ||
399 | pci_disable_device(chip->pci); | ||
400 | } | ||
401 | |||
402 | int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | ||
403 | int midi, const struct oxygen_model *model) | ||
404 | { | ||
405 | struct snd_card *card; | ||
406 | struct oxygen *chip; | ||
407 | int err; | ||
408 | |||
409 | card = snd_card_new(index, id, model->owner, | ||
410 | sizeof *chip + model->model_data_size); | ||
411 | if (!card) | ||
412 | return -ENOMEM; | ||
413 | |||
414 | chip = card->private_data; | ||
415 | chip->card = card; | ||
416 | chip->pci = pci; | ||
417 | chip->irq = -1; | ||
418 | chip->model = model; | ||
419 | chip->model_data = chip + 1; | ||
420 | spin_lock_init(&chip->reg_lock); | ||
421 | mutex_init(&chip->mutex); | ||
422 | INIT_WORK(&chip->spdif_input_bits_work, | ||
423 | oxygen_spdif_input_bits_changed); | ||
424 | INIT_WORK(&chip->gpio_work, oxygen_gpio_changed); | ||
425 | init_waitqueue_head(&chip->ac97_waitqueue); | ||
426 | |||
427 | err = pci_enable_device(pci); | ||
428 | if (err < 0) | ||
429 | goto err_card; | ||
430 | |||
431 | err = pci_request_regions(pci, model->chip); | ||
432 | if (err < 0) { | ||
433 | snd_printk(KERN_ERR "cannot reserve PCI resources\n"); | ||
434 | goto err_pci_enable; | ||
435 | } | ||
436 | |||
437 | if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || | ||
438 | pci_resource_len(pci, 0) < 0x100) { | ||
439 | snd_printk(KERN_ERR "invalid PCI I/O range\n"); | ||
440 | err = -ENXIO; | ||
441 | goto err_pci_regions; | ||
442 | } | ||
443 | chip->addr = pci_resource_start(pci, 0); | ||
444 | |||
445 | pci_set_master(pci); | ||
446 | snd_card_set_dev(card, &pci->dev); | ||
447 | card->private_free = oxygen_card_free; | ||
448 | |||
449 | oxygen_init(chip); | ||
450 | model->init(chip); | ||
451 | |||
452 | err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, | ||
453 | model->chip, chip); | ||
454 | if (err < 0) { | ||
455 | snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); | ||
456 | goto err_card; | ||
457 | } | ||
458 | chip->irq = pci->irq; | ||
459 | |||
460 | strcpy(card->driver, model->chip); | ||
461 | strcpy(card->shortname, model->shortname); | ||
462 | sprintf(card->longname, "%s (rev %u) at %#lx, irq %i", | ||
463 | model->longname, chip->revision, chip->addr, chip->irq); | ||
464 | strcpy(card->mixername, model->chip); | ||
465 | snd_component_add(card, model->chip); | ||
466 | |||
467 | err = oxygen_pcm_init(chip); | ||
468 | if (err < 0) | ||
469 | goto err_card; | ||
470 | |||
471 | err = oxygen_mixer_init(chip); | ||
472 | if (err < 0) | ||
473 | goto err_card; | ||
474 | |||
475 | oxygen_write8_masked(chip, OXYGEN_MISC, | ||
476 | midi ? OXYGEN_MISC_MIDI : 0, OXYGEN_MISC_MIDI); | ||
477 | if (midi) { | ||
478 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, | ||
479 | chip->addr + OXYGEN_MPU401, | ||
480 | MPU401_INFO_INTEGRATED, 0, 0, | ||
481 | &chip->midi); | ||
482 | if (err < 0) | ||
483 | goto err_card; | ||
484 | } | ||
485 | |||
486 | oxygen_proc_init(chip); | ||
487 | |||
488 | spin_lock_irq(&chip->reg_lock); | ||
489 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_AC97; | ||
490 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
491 | spin_unlock_irq(&chip->reg_lock); | ||
492 | |||
493 | err = snd_card_register(card); | ||
494 | if (err < 0) | ||
495 | goto err_card; | ||
496 | |||
497 | pci_set_drvdata(pci, card); | ||
498 | return 0; | ||
499 | |||
500 | err_pci_regions: | ||
501 | pci_release_regions(pci); | ||
502 | err_pci_enable: | ||
503 | pci_disable_device(pci); | ||
504 | err_card: | ||
505 | snd_card_free(card); | ||
506 | return err; | ||
507 | } | ||
508 | EXPORT_SYMBOL(oxygen_pci_probe); | ||
509 | |||
510 | void __devexit oxygen_pci_remove(struct pci_dev *pci) | ||
511 | { | ||
512 | snd_card_free(pci_get_drvdata(pci)); | ||
513 | pci_set_drvdata(pci, NULL); | ||
514 | } | ||
515 | EXPORT_SYMBOL(oxygen_pci_remove); | ||
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c new file mode 100644 index 000000000000..a8e4623415d9 --- /dev/null +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -0,0 +1,794 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - mixer code | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/mutex.h> | ||
21 | #include <sound/ac97_codec.h> | ||
22 | #include <sound/asoundef.h> | ||
23 | #include <sound/control.h> | ||
24 | #include <sound/tlv.h> | ||
25 | #include "oxygen.h" | ||
26 | #include "cm9780.h" | ||
27 | |||
28 | static int dac_volume_info(struct snd_kcontrol *ctl, | ||
29 | struct snd_ctl_elem_info *info) | ||
30 | { | ||
31 | struct oxygen *chip = ctl->private_data; | ||
32 | |||
33 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
34 | info->count = chip->model->dac_channels; | ||
35 | info->value.integer.min = 0; | ||
36 | info->value.integer.max = 0xff; | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int dac_volume_get(struct snd_kcontrol *ctl, | ||
41 | struct snd_ctl_elem_value *value) | ||
42 | { | ||
43 | struct oxygen *chip = ctl->private_data; | ||
44 | unsigned int i; | ||
45 | |||
46 | mutex_lock(&chip->mutex); | ||
47 | for (i = 0; i < chip->model->dac_channels; ++i) | ||
48 | value->value.integer.value[i] = chip->dac_volume[i]; | ||
49 | mutex_unlock(&chip->mutex); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int dac_volume_put(struct snd_kcontrol *ctl, | ||
54 | struct snd_ctl_elem_value *value) | ||
55 | { | ||
56 | struct oxygen *chip = ctl->private_data; | ||
57 | unsigned int i; | ||
58 | int changed; | ||
59 | |||
60 | changed = 0; | ||
61 | mutex_lock(&chip->mutex); | ||
62 | for (i = 0; i < chip->model->dac_channels; ++i) | ||
63 | if (value->value.integer.value[i] != chip->dac_volume[i]) { | ||
64 | chip->dac_volume[i] = value->value.integer.value[i]; | ||
65 | changed = 1; | ||
66 | } | ||
67 | if (changed) | ||
68 | chip->model->update_dac_volume(chip); | ||
69 | mutex_unlock(&chip->mutex); | ||
70 | return changed; | ||
71 | } | ||
72 | |||
73 | static int dac_mute_get(struct snd_kcontrol *ctl, | ||
74 | struct snd_ctl_elem_value *value) | ||
75 | { | ||
76 | struct oxygen *chip = ctl->private_data; | ||
77 | |||
78 | mutex_lock(&chip->mutex); | ||
79 | value->value.integer.value[0] = !chip->dac_mute; | ||
80 | mutex_unlock(&chip->mutex); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int dac_mute_put(struct snd_kcontrol *ctl, | ||
85 | struct snd_ctl_elem_value *value) | ||
86 | { | ||
87 | struct oxygen *chip = ctl->private_data; | ||
88 | int changed; | ||
89 | |||
90 | mutex_lock(&chip->mutex); | ||
91 | changed = !value->value.integer.value[0] != chip->dac_mute; | ||
92 | if (changed) { | ||
93 | chip->dac_mute = !value->value.integer.value[0]; | ||
94 | chip->model->update_dac_mute(chip); | ||
95 | } | ||
96 | mutex_unlock(&chip->mutex); | ||
97 | return changed; | ||
98 | } | ||
99 | |||
100 | static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
101 | { | ||
102 | static const char *const names[3] = { | ||
103 | "Front", "Front+Surround", "Front+Surround+Back" | ||
104 | }; | ||
105 | struct oxygen *chip = ctl->private_data; | ||
106 | unsigned int count = 2 + (chip->model->dac_channels == 8); | ||
107 | |||
108 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
109 | info->count = 1; | ||
110 | info->value.enumerated.items = count; | ||
111 | if (info->value.enumerated.item >= count) | ||
112 | info->value.enumerated.item = count - 1; | ||
113 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
118 | { | ||
119 | struct oxygen *chip = ctl->private_data; | ||
120 | |||
121 | mutex_lock(&chip->mutex); | ||
122 | value->value.enumerated.item[0] = chip->dac_routing; | ||
123 | mutex_unlock(&chip->mutex); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | void oxygen_update_dac_routing(struct oxygen *chip) | ||
128 | { | ||
129 | /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ | ||
130 | static const unsigned int reg_values[3] = { | ||
131 | /* stereo -> front */ | ||
132 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
133 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
134 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
135 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
136 | /* stereo -> front+surround */ | ||
137 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
138 | (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
139 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
140 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
141 | /* stereo -> front+surround+back */ | ||
142 | (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
143 | (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
144 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
145 | (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), | ||
146 | }; | ||
147 | u8 channels; | ||
148 | unsigned int reg_value; | ||
149 | |||
150 | channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) & | ||
151 | OXYGEN_PLAY_CHANNELS_MASK; | ||
152 | if (channels == OXYGEN_PLAY_CHANNELS_2) | ||
153 | reg_value = reg_values[chip->dac_routing]; | ||
154 | else if (channels == OXYGEN_PLAY_CHANNELS_8) | ||
155 | /* in 7.1 mode, "rear" channels go to the "back" jack */ | ||
156 | reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
157 | (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
158 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
159 | (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); | ||
160 | else | ||
161 | reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | | ||
162 | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | | ||
163 | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | | ||
164 | (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT); | ||
165 | oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, | ||
166 | OXYGEN_PLAY_DAC0_SOURCE_MASK | | ||
167 | OXYGEN_PLAY_DAC1_SOURCE_MASK | | ||
168 | OXYGEN_PLAY_DAC2_SOURCE_MASK | | ||
169 | OXYGEN_PLAY_DAC3_SOURCE_MASK); | ||
170 | } | ||
171 | |||
172 | static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
173 | { | ||
174 | struct oxygen *chip = ctl->private_data; | ||
175 | unsigned int count = 2 + (chip->model->dac_channels == 8); | ||
176 | int changed; | ||
177 | |||
178 | mutex_lock(&chip->mutex); | ||
179 | changed = value->value.enumerated.item[0] != chip->dac_routing; | ||
180 | if (changed) { | ||
181 | chip->dac_routing = min(value->value.enumerated.item[0], | ||
182 | count - 1); | ||
183 | spin_lock_irq(&chip->reg_lock); | ||
184 | oxygen_update_dac_routing(chip); | ||
185 | spin_unlock_irq(&chip->reg_lock); | ||
186 | } | ||
187 | mutex_unlock(&chip->mutex); | ||
188 | return changed; | ||
189 | } | ||
190 | |||
191 | static int spdif_switch_get(struct snd_kcontrol *ctl, | ||
192 | struct snd_ctl_elem_value *value) | ||
193 | { | ||
194 | struct oxygen *chip = ctl->private_data; | ||
195 | |||
196 | mutex_lock(&chip->mutex); | ||
197 | value->value.integer.value[0] = chip->spdif_playback_enable; | ||
198 | mutex_unlock(&chip->mutex); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate) | ||
203 | { | ||
204 | switch (oxygen_rate) { | ||
205 | case OXYGEN_RATE_32000: | ||
206 | return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
207 | case OXYGEN_RATE_44100: | ||
208 | return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
209 | default: /* OXYGEN_RATE_48000 */ | ||
210 | return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
211 | case OXYGEN_RATE_64000: | ||
212 | return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
213 | case OXYGEN_RATE_88200: | ||
214 | return 0x8 << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
215 | case OXYGEN_RATE_96000: | ||
216 | return 0xa << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
217 | case OXYGEN_RATE_176400: | ||
218 | return 0xc << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
219 | case OXYGEN_RATE_192000: | ||
220 | return 0xe << OXYGEN_SPDIF_CS_RATE_SHIFT; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | void oxygen_update_spdif_source(struct oxygen *chip) | ||
225 | { | ||
226 | u32 old_control, new_control; | ||
227 | u16 old_routing, new_routing; | ||
228 | unsigned int oxygen_rate; | ||
229 | |||
230 | old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
231 | old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING); | ||
232 | if (chip->pcm_active & (1 << PCM_SPDIF)) { | ||
233 | new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE; | ||
234 | new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) | ||
235 | | OXYGEN_PLAY_SPDIF_SPDIF; | ||
236 | oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT) | ||
237 | & OXYGEN_I2S_RATE_MASK; | ||
238 | /* S/PDIF rate was already set by the caller */ | ||
239 | } else if ((chip->pcm_active & (1 << PCM_MULTICH)) && | ||
240 | chip->spdif_playback_enable) { | ||
241 | new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK) | ||
242 | | OXYGEN_PLAY_SPDIF_MULTICH_01; | ||
243 | oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) | ||
244 | & OXYGEN_I2S_RATE_MASK; | ||
245 | new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) | | ||
246 | (oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) | | ||
247 | OXYGEN_SPDIF_OUT_ENABLE; | ||
248 | } else { | ||
249 | new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE; | ||
250 | new_routing = old_routing; | ||
251 | oxygen_rate = OXYGEN_RATE_44100; | ||
252 | } | ||
253 | if (old_routing != new_routing) { | ||
254 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, | ||
255 | new_control & ~OXYGEN_SPDIF_OUT_ENABLE); | ||
256 | oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing); | ||
257 | } | ||
258 | if (new_control & OXYGEN_SPDIF_OUT_ENABLE) | ||
259 | oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS, | ||
260 | oxygen_spdif_rate(oxygen_rate) | | ||
261 | ((chip->pcm_active & (1 << PCM_SPDIF)) ? | ||
262 | chip->spdif_pcm_bits : chip->spdif_bits)); | ||
263 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control); | ||
264 | } | ||
265 | |||
266 | static int spdif_switch_put(struct snd_kcontrol *ctl, | ||
267 | struct snd_ctl_elem_value *value) | ||
268 | { | ||
269 | struct oxygen *chip = ctl->private_data; | ||
270 | int changed; | ||
271 | |||
272 | mutex_lock(&chip->mutex); | ||
273 | changed = value->value.integer.value[0] != chip->spdif_playback_enable; | ||
274 | if (changed) { | ||
275 | chip->spdif_playback_enable = !!value->value.integer.value[0]; | ||
276 | spin_lock_irq(&chip->reg_lock); | ||
277 | oxygen_update_spdif_source(chip); | ||
278 | spin_unlock_irq(&chip->reg_lock); | ||
279 | } | ||
280 | mutex_unlock(&chip->mutex); | ||
281 | return changed; | ||
282 | } | ||
283 | |||
284 | static int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
285 | { | ||
286 | info->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
287 | info->count = 1; | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value) | ||
292 | { | ||
293 | value->value.iec958.status[0] = | ||
294 | bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | | ||
295 | OXYGEN_SPDIF_PREEMPHASIS); | ||
296 | value->value.iec958.status[1] = /* category and original */ | ||
297 | bits >> OXYGEN_SPDIF_CATEGORY_SHIFT; | ||
298 | } | ||
299 | |||
300 | static u32 iec958_to_oxygen(struct snd_ctl_elem_value *value) | ||
301 | { | ||
302 | u32 bits; | ||
303 | |||
304 | bits = value->value.iec958.status[0] & | ||
305 | (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C | | ||
306 | OXYGEN_SPDIF_PREEMPHASIS); | ||
307 | bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT; | ||
308 | if (bits & OXYGEN_SPDIF_NONAUDIO) | ||
309 | bits |= OXYGEN_SPDIF_V; | ||
310 | return bits; | ||
311 | } | ||
312 | |||
313 | static inline void write_spdif_bits(struct oxygen *chip, u32 bits) | ||
314 | { | ||
315 | oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits, | ||
316 | OXYGEN_SPDIF_NONAUDIO | | ||
317 | OXYGEN_SPDIF_C | | ||
318 | OXYGEN_SPDIF_PREEMPHASIS | | ||
319 | OXYGEN_SPDIF_CATEGORY_MASK | | ||
320 | OXYGEN_SPDIF_ORIGINAL | | ||
321 | OXYGEN_SPDIF_V); | ||
322 | } | ||
323 | |||
324 | static int spdif_default_get(struct snd_kcontrol *ctl, | ||
325 | struct snd_ctl_elem_value *value) | ||
326 | { | ||
327 | struct oxygen *chip = ctl->private_data; | ||
328 | |||
329 | mutex_lock(&chip->mutex); | ||
330 | oxygen_to_iec958(chip->spdif_bits, value); | ||
331 | mutex_unlock(&chip->mutex); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int spdif_default_put(struct snd_kcontrol *ctl, | ||
336 | struct snd_ctl_elem_value *value) | ||
337 | { | ||
338 | struct oxygen *chip = ctl->private_data; | ||
339 | u32 new_bits; | ||
340 | int changed; | ||
341 | |||
342 | new_bits = iec958_to_oxygen(value); | ||
343 | mutex_lock(&chip->mutex); | ||
344 | changed = new_bits != chip->spdif_bits; | ||
345 | if (changed) { | ||
346 | chip->spdif_bits = new_bits; | ||
347 | if (!(chip->pcm_active & (1 << PCM_SPDIF))) | ||
348 | write_spdif_bits(chip, new_bits); | ||
349 | } | ||
350 | mutex_unlock(&chip->mutex); | ||
351 | return changed; | ||
352 | } | ||
353 | |||
354 | static int spdif_mask_get(struct snd_kcontrol *ctl, | ||
355 | struct snd_ctl_elem_value *value) | ||
356 | { | ||
357 | value->value.iec958.status[0] = IEC958_AES0_NONAUDIO | | ||
358 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS; | ||
359 | value->value.iec958.status[1] = | ||
360 | IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int spdif_pcm_get(struct snd_kcontrol *ctl, | ||
365 | struct snd_ctl_elem_value *value) | ||
366 | { | ||
367 | struct oxygen *chip = ctl->private_data; | ||
368 | |||
369 | mutex_lock(&chip->mutex); | ||
370 | oxygen_to_iec958(chip->spdif_pcm_bits, value); | ||
371 | mutex_unlock(&chip->mutex); | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | static int spdif_pcm_put(struct snd_kcontrol *ctl, | ||
376 | struct snd_ctl_elem_value *value) | ||
377 | { | ||
378 | struct oxygen *chip = ctl->private_data; | ||
379 | u32 new_bits; | ||
380 | int changed; | ||
381 | |||
382 | new_bits = iec958_to_oxygen(value); | ||
383 | mutex_lock(&chip->mutex); | ||
384 | changed = new_bits != chip->spdif_pcm_bits; | ||
385 | if (changed) { | ||
386 | chip->spdif_pcm_bits = new_bits; | ||
387 | if (chip->pcm_active & (1 << PCM_SPDIF)) | ||
388 | write_spdif_bits(chip, new_bits); | ||
389 | } | ||
390 | mutex_unlock(&chip->mutex); | ||
391 | return changed; | ||
392 | } | ||
393 | |||
394 | static int spdif_input_mask_get(struct snd_kcontrol *ctl, | ||
395 | struct snd_ctl_elem_value *value) | ||
396 | { | ||
397 | value->value.iec958.status[0] = 0xff; | ||
398 | value->value.iec958.status[1] = 0xff; | ||
399 | value->value.iec958.status[2] = 0xff; | ||
400 | value->value.iec958.status[3] = 0xff; | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int spdif_input_default_get(struct snd_kcontrol *ctl, | ||
405 | struct snd_ctl_elem_value *value) | ||
406 | { | ||
407 | struct oxygen *chip = ctl->private_data; | ||
408 | u32 bits; | ||
409 | |||
410 | bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS); | ||
411 | value->value.iec958.status[0] = bits; | ||
412 | value->value.iec958.status[1] = bits >> 8; | ||
413 | value->value.iec958.status[2] = bits >> 16; | ||
414 | value->value.iec958.status[3] = bits >> 24; | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int spdif_loopback_get(struct snd_kcontrol *ctl, | ||
419 | struct snd_ctl_elem_value *value) | ||
420 | { | ||
421 | struct oxygen *chip = ctl->private_data; | ||
422 | |||
423 | value->value.integer.value[0] = | ||
424 | !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) | ||
425 | & OXYGEN_SPDIF_LOOPBACK); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int spdif_loopback_put(struct snd_kcontrol *ctl, | ||
430 | struct snd_ctl_elem_value *value) | ||
431 | { | ||
432 | struct oxygen *chip = ctl->private_data; | ||
433 | u32 oldreg, newreg; | ||
434 | int changed; | ||
435 | |||
436 | spin_lock_irq(&chip->reg_lock); | ||
437 | oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL); | ||
438 | if (value->value.integer.value[0]) | ||
439 | newreg = oldreg | OXYGEN_SPDIF_LOOPBACK; | ||
440 | else | ||
441 | newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK; | ||
442 | changed = newreg != oldreg; | ||
443 | if (changed) | ||
444 | oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg); | ||
445 | spin_unlock_irq(&chip->reg_lock); | ||
446 | return changed; | ||
447 | } | ||
448 | |||
449 | static int ac97_switch_get(struct snd_kcontrol *ctl, | ||
450 | struct snd_ctl_elem_value *value) | ||
451 | { | ||
452 | struct oxygen *chip = ctl->private_data; | ||
453 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
454 | unsigned int index = ctl->private_value & 0xff; | ||
455 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | ||
456 | int invert = ctl->private_value & (1 << 16); | ||
457 | u16 reg; | ||
458 | |||
459 | mutex_lock(&chip->mutex); | ||
460 | reg = oxygen_read_ac97(chip, codec, index); | ||
461 | mutex_unlock(&chip->mutex); | ||
462 | if (!(reg & (1 << bitnr)) ^ !invert) | ||
463 | value->value.integer.value[0] = 1; | ||
464 | else | ||
465 | value->value.integer.value[0] = 0; | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int ac97_switch_put(struct snd_kcontrol *ctl, | ||
470 | struct snd_ctl_elem_value *value) | ||
471 | { | ||
472 | struct oxygen *chip = ctl->private_data; | ||
473 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
474 | unsigned int index = ctl->private_value & 0xff; | ||
475 | unsigned int bitnr = (ctl->private_value >> 8) & 0xff; | ||
476 | int invert = ctl->private_value & (1 << 16); | ||
477 | u16 oldreg, newreg; | ||
478 | int change; | ||
479 | |||
480 | mutex_lock(&chip->mutex); | ||
481 | oldreg = oxygen_read_ac97(chip, codec, index); | ||
482 | newreg = oldreg; | ||
483 | if (!value->value.integer.value[0] ^ !invert) | ||
484 | newreg |= 1 << bitnr; | ||
485 | else | ||
486 | newreg &= ~(1 << bitnr); | ||
487 | change = newreg != oldreg; | ||
488 | if (change) { | ||
489 | oxygen_write_ac97(chip, codec, index, newreg); | ||
490 | if (bitnr == 15 && chip->model->ac97_switch_hook) | ||
491 | chip->model->ac97_switch_hook(chip, codec, index, | ||
492 | newreg & 0x8000); | ||
493 | } | ||
494 | mutex_unlock(&chip->mutex); | ||
495 | return change; | ||
496 | } | ||
497 | |||
498 | static int ac97_volume_info(struct snd_kcontrol *ctl, | ||
499 | struct snd_ctl_elem_info *info) | ||
500 | { | ||
501 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
502 | info->count = 2; | ||
503 | info->value.integer.min = 0; | ||
504 | info->value.integer.max = 0x1f; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int ac97_volume_get(struct snd_kcontrol *ctl, | ||
509 | struct snd_ctl_elem_value *value) | ||
510 | { | ||
511 | struct oxygen *chip = ctl->private_data; | ||
512 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
513 | unsigned int index = ctl->private_value & 0xff; | ||
514 | u16 reg; | ||
515 | |||
516 | mutex_lock(&chip->mutex); | ||
517 | reg = oxygen_read_ac97(chip, codec, index); | ||
518 | mutex_unlock(&chip->mutex); | ||
519 | value->value.integer.value[0] = 31 - (reg & 0x1f); | ||
520 | value->value.integer.value[1] = 31 - ((reg >> 8) & 0x1f); | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int ac97_volume_put(struct snd_kcontrol *ctl, | ||
525 | struct snd_ctl_elem_value *value) | ||
526 | { | ||
527 | struct oxygen *chip = ctl->private_data; | ||
528 | unsigned int codec = (ctl->private_value >> 24) & 1; | ||
529 | unsigned int index = ctl->private_value & 0xff; | ||
530 | u16 oldreg, newreg; | ||
531 | int change; | ||
532 | |||
533 | mutex_lock(&chip->mutex); | ||
534 | oldreg = oxygen_read_ac97(chip, codec, index); | ||
535 | newreg = oldreg; | ||
536 | newreg = (newreg & ~0x1f) | | ||
537 | (31 - (value->value.integer.value[0] & 0x1f)); | ||
538 | newreg = (newreg & ~0x1f00) | | ||
539 | ((31 - (value->value.integer.value[0] & 0x1f)) << 8); | ||
540 | change = newreg != oldreg; | ||
541 | if (change) | ||
542 | oxygen_write_ac97(chip, codec, index, newreg); | ||
543 | mutex_unlock(&chip->mutex); | ||
544 | return change; | ||
545 | } | ||
546 | |||
547 | static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl, | ||
548 | struct snd_ctl_elem_info *info) | ||
549 | { | ||
550 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
551 | info->count = 2; | ||
552 | info->value.integer.min = 0; | ||
553 | info->value.integer.max = 7; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl, | ||
558 | struct snd_ctl_elem_value *value) | ||
559 | { | ||
560 | struct oxygen *chip = ctl->private_data; | ||
561 | u16 reg; | ||
562 | |||
563 | mutex_lock(&chip->mutex); | ||
564 | reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
565 | mutex_unlock(&chip->mutex); | ||
566 | value->value.integer.value[0] = reg & 7; | ||
567 | value->value.integer.value[1] = (reg >> 8) & 7; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl, | ||
572 | struct snd_ctl_elem_value *value) | ||
573 | { | ||
574 | struct oxygen *chip = ctl->private_data; | ||
575 | u16 oldreg, newreg; | ||
576 | int change; | ||
577 | |||
578 | mutex_lock(&chip->mutex); | ||
579 | oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN); | ||
580 | newreg = oldreg & ~0x0707; | ||
581 | newreg = newreg | (value->value.integer.value[0] & 7); | ||
582 | newreg = newreg | ((value->value.integer.value[0] & 7) << 8); | ||
583 | change = newreg != oldreg; | ||
584 | if (change) | ||
585 | oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg); | ||
586 | mutex_unlock(&chip->mutex); | ||
587 | return change; | ||
588 | } | ||
589 | |||
590 | #define AC97_SWITCH(xname, codec, index, bitnr, invert) { \ | ||
591 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
592 | .name = xname, \ | ||
593 | .info = snd_ctl_boolean_mono_info, \ | ||
594 | .get = ac97_switch_get, \ | ||
595 | .put = ac97_switch_put, \ | ||
596 | .private_value = ((codec) << 24) | ((invert) << 16) | \ | ||
597 | ((bitnr) << 8) | (index), \ | ||
598 | } | ||
599 | #define AC97_VOLUME(xname, codec, index) { \ | ||
600 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
601 | .name = xname, \ | ||
602 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
603 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
604 | .info = ac97_volume_info, \ | ||
605 | .get = ac97_volume_get, \ | ||
606 | .put = ac97_volume_put, \ | ||
607 | .tlv = { .p = ac97_db_scale, }, \ | ||
608 | .private_value = ((codec) << 24) | (index), \ | ||
609 | } | ||
610 | |||
611 | static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0); | ||
612 | static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0); | ||
613 | |||
614 | static const struct snd_kcontrol_new controls[] = { | ||
615 | { | ||
616 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
617 | .name = "Master Playback Volume", | ||
618 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
619 | .info = dac_volume_info, | ||
620 | .get = dac_volume_get, | ||
621 | .put = dac_volume_put, | ||
622 | }, | ||
623 | { | ||
624 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
625 | .name = "Master Playback Switch", | ||
626 | .info = snd_ctl_boolean_mono_info, | ||
627 | .get = dac_mute_get, | ||
628 | .put = dac_mute_put, | ||
629 | }, | ||
630 | { | ||
631 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
632 | .name = "Stereo Upmixing", | ||
633 | .info = upmix_info, | ||
634 | .get = upmix_get, | ||
635 | .put = upmix_put, | ||
636 | }, | ||
637 | { | ||
638 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
639 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), | ||
640 | .info = snd_ctl_boolean_mono_info, | ||
641 | .get = spdif_switch_get, | ||
642 | .put = spdif_switch_put, | ||
643 | }, | ||
644 | { | ||
645 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
646 | .device = 1, | ||
647 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
648 | .info = spdif_info, | ||
649 | .get = spdif_default_get, | ||
650 | .put = spdif_default_put, | ||
651 | }, | ||
652 | { | ||
653 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
654 | .device = 1, | ||
655 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), | ||
656 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
657 | .info = spdif_info, | ||
658 | .get = spdif_mask_get, | ||
659 | }, | ||
660 | { | ||
661 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
662 | .device = 1, | ||
663 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), | ||
664 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
665 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
666 | .info = spdif_info, | ||
667 | .get = spdif_pcm_get, | ||
668 | .put = spdif_pcm_put, | ||
669 | }, | ||
670 | { | ||
671 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
672 | .device = 1, | ||
673 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), | ||
674 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
675 | .info = spdif_info, | ||
676 | .get = spdif_input_mask_get, | ||
677 | }, | ||
678 | { | ||
679 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
680 | .device = 1, | ||
681 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
682 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
683 | .info = spdif_info, | ||
684 | .get = spdif_input_default_get, | ||
685 | }, | ||
686 | { | ||
687 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
688 | .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH), | ||
689 | .info = snd_ctl_boolean_mono_info, | ||
690 | .get = spdif_loopback_get, | ||
691 | .put = spdif_loopback_put, | ||
692 | }, | ||
693 | }; | ||
694 | |||
695 | static const struct snd_kcontrol_new ac97_controls[] = { | ||
696 | AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC), | ||
697 | AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1), | ||
698 | AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0), | ||
699 | AC97_VOLUME("Line Capture Volume", 0, AC97_LINE), | ||
700 | AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1), | ||
701 | AC97_VOLUME("CD Capture Volume", 0, AC97_CD), | ||
702 | AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1), | ||
703 | AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX), | ||
704 | AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1), | ||
705 | }; | ||
706 | |||
707 | static const struct snd_kcontrol_new ac97_fp_controls[] = { | ||
708 | AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE), | ||
709 | AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1), | ||
710 | { | ||
711 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
712 | .name = "Front Panel Capture Volume", | ||
713 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
714 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
715 | .info = ac97_fp_rec_volume_info, | ||
716 | .get = ac97_fp_rec_volume_get, | ||
717 | .put = ac97_fp_rec_volume_put, | ||
718 | .tlv = { .p = ac97_rec_db_scale, }, | ||
719 | }, | ||
720 | AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1), | ||
721 | }; | ||
722 | |||
723 | static void oxygen_any_ctl_free(struct snd_kcontrol *ctl) | ||
724 | { | ||
725 | struct oxygen *chip = ctl->private_data; | ||
726 | unsigned int i; | ||
727 | |||
728 | /* I'm too lazy to write a function for each control :-) */ | ||
729 | for (i = 0; i < ARRAY_SIZE(chip->controls); ++i) | ||
730 | chip->controls[i] = NULL; | ||
731 | } | ||
732 | |||
733 | static int add_controls(struct oxygen *chip, | ||
734 | const struct snd_kcontrol_new controls[], | ||
735 | unsigned int count) | ||
736 | { | ||
737 | static const char *const known_ctl_names[CONTROL_COUNT] = { | ||
738 | [CONTROL_SPDIF_PCM] = | ||
739 | SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), | ||
740 | [CONTROL_SPDIF_INPUT_BITS] = | ||
741 | SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
742 | [CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch", | ||
743 | [CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch", | ||
744 | [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", | ||
745 | [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", | ||
746 | }; | ||
747 | unsigned int i, j; | ||
748 | struct snd_kcontrol_new template; | ||
749 | struct snd_kcontrol *ctl; | ||
750 | int err; | ||
751 | |||
752 | for (i = 0; i < count; ++i) { | ||
753 | template = controls[i]; | ||
754 | err = chip->model->control_filter(&template); | ||
755 | if (err < 0) | ||
756 | return err; | ||
757 | if (err == 1) | ||
758 | continue; | ||
759 | ctl = snd_ctl_new1(&template, chip); | ||
760 | if (!ctl) | ||
761 | return -ENOMEM; | ||
762 | err = snd_ctl_add(chip->card, ctl); | ||
763 | if (err < 0) | ||
764 | return err; | ||
765 | for (j = 0; j < CONTROL_COUNT; ++j) | ||
766 | if (!strcmp(ctl->id.name, known_ctl_names[j])) { | ||
767 | chip->controls[j] = ctl; | ||
768 | ctl->private_free = oxygen_any_ctl_free; | ||
769 | } | ||
770 | } | ||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | int oxygen_mixer_init(struct oxygen *chip) | ||
775 | { | ||
776 | int err; | ||
777 | |||
778 | err = add_controls(chip, controls, ARRAY_SIZE(controls)); | ||
779 | if (err < 0) | ||
780 | return err; | ||
781 | if (chip->has_ac97_0) { | ||
782 | err = add_controls(chip, ac97_controls, | ||
783 | ARRAY_SIZE(ac97_controls)); | ||
784 | if (err < 0) | ||
785 | return err; | ||
786 | } | ||
787 | if (chip->has_ac97_1) { | ||
788 | err = add_controls(chip, ac97_fp_controls, | ||
789 | ARRAY_SIZE(ac97_fp_controls)); | ||
790 | if (err < 0) | ||
791 | return err; | ||
792 | } | ||
793 | return chip->model->mixer_init ? chip->model->mixer_init(chip) : 0; | ||
794 | } | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c new file mode 100644 index 000000000000..dfad3db35c82 --- /dev/null +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -0,0 +1,718 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver - PCM code | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/pci.h> | ||
21 | #include <sound/control.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include "oxygen.h" | ||
26 | |||
27 | static const struct snd_pcm_hardware oxygen_stereo_hardware = { | ||
28 | .info = SNDRV_PCM_INFO_MMAP | | ||
29 | SNDRV_PCM_INFO_MMAP_VALID | | ||
30 | SNDRV_PCM_INFO_INTERLEAVED | | ||
31 | SNDRV_PCM_INFO_PAUSE | | ||
32 | SNDRV_PCM_INFO_SYNC_START, | ||
33 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
34 | SNDRV_PCM_FMTBIT_S32_LE, | ||
35 | .rates = SNDRV_PCM_RATE_32000 | | ||
36 | SNDRV_PCM_RATE_44100 | | ||
37 | SNDRV_PCM_RATE_48000 | | ||
38 | SNDRV_PCM_RATE_64000 | | ||
39 | SNDRV_PCM_RATE_88200 | | ||
40 | SNDRV_PCM_RATE_96000 | | ||
41 | SNDRV_PCM_RATE_176400 | | ||
42 | SNDRV_PCM_RATE_192000, | ||
43 | .rate_min = 32000, | ||
44 | .rate_max = 192000, | ||
45 | .channels_min = 2, | ||
46 | .channels_max = 2, | ||
47 | .buffer_bytes_max = 256 * 1024, | ||
48 | .period_bytes_min = 128, | ||
49 | .period_bytes_max = 128 * 1024, | ||
50 | .periods_min = 2, | ||
51 | .periods_max = 2048, | ||
52 | }; | ||
53 | static const struct snd_pcm_hardware oxygen_multichannel_hardware = { | ||
54 | .info = SNDRV_PCM_INFO_MMAP | | ||
55 | SNDRV_PCM_INFO_MMAP_VALID | | ||
56 | SNDRV_PCM_INFO_INTERLEAVED | | ||
57 | SNDRV_PCM_INFO_PAUSE | | ||
58 | SNDRV_PCM_INFO_SYNC_START, | ||
59 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
60 | SNDRV_PCM_FMTBIT_S32_LE, | ||
61 | .rates = SNDRV_PCM_RATE_32000 | | ||
62 | SNDRV_PCM_RATE_44100 | | ||
63 | SNDRV_PCM_RATE_48000 | | ||
64 | SNDRV_PCM_RATE_64000 | | ||
65 | SNDRV_PCM_RATE_88200 | | ||
66 | SNDRV_PCM_RATE_96000 | | ||
67 | SNDRV_PCM_RATE_176400 | | ||
68 | SNDRV_PCM_RATE_192000, | ||
69 | .rate_min = 32000, | ||
70 | .rate_max = 192000, | ||
71 | .channels_min = 2, | ||
72 | .channels_max = 8, | ||
73 | .buffer_bytes_max = 2048 * 1024, | ||
74 | .period_bytes_min = 128, | ||
75 | .period_bytes_max = 256 * 1024, | ||
76 | .periods_min = 2, | ||
77 | .periods_max = 16384, | ||
78 | }; | ||
79 | static const struct snd_pcm_hardware oxygen_ac97_hardware = { | ||
80 | .info = SNDRV_PCM_INFO_MMAP | | ||
81 | SNDRV_PCM_INFO_MMAP_VALID | | ||
82 | SNDRV_PCM_INFO_INTERLEAVED | | ||
83 | SNDRV_PCM_INFO_PAUSE | | ||
84 | SNDRV_PCM_INFO_SYNC_START, | ||
85 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
86 | .rates = SNDRV_PCM_RATE_48000, | ||
87 | .rate_min = 48000, | ||
88 | .rate_max = 48000, | ||
89 | .channels_min = 2, | ||
90 | .channels_max = 2, | ||
91 | .buffer_bytes_max = 256 * 1024, | ||
92 | .period_bytes_min = 128, | ||
93 | .period_bytes_max = 128 * 1024, | ||
94 | .periods_min = 2, | ||
95 | .periods_max = 2048, | ||
96 | }; | ||
97 | |||
98 | static const struct snd_pcm_hardware *const oxygen_hardware[PCM_COUNT] = { | ||
99 | [PCM_A] = &oxygen_stereo_hardware, | ||
100 | [PCM_B] = &oxygen_stereo_hardware, | ||
101 | [PCM_C] = &oxygen_stereo_hardware, | ||
102 | [PCM_SPDIF] = &oxygen_stereo_hardware, | ||
103 | [PCM_MULTICH] = &oxygen_multichannel_hardware, | ||
104 | [PCM_AC97] = &oxygen_ac97_hardware, | ||
105 | }; | ||
106 | |||
107 | static inline unsigned int | ||
108 | oxygen_substream_channel(struct snd_pcm_substream *substream) | ||
109 | { | ||
110 | return (unsigned int)(uintptr_t)substream->runtime->private_data; | ||
111 | } | ||
112 | |||
113 | static int oxygen_open(struct snd_pcm_substream *substream, | ||
114 | unsigned int channel) | ||
115 | { | ||
116 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
117 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
118 | int err; | ||
119 | |||
120 | runtime->private_data = (void *)(uintptr_t)channel; | ||
121 | if (channel == PCM_B && chip->has_ac97_1 && | ||
122 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97)) | ||
123 | runtime->hw = oxygen_ac97_hardware; | ||
124 | else | ||
125 | runtime->hw = *oxygen_hardware[channel]; | ||
126 | switch (channel) { | ||
127 | case PCM_C: | ||
128 | runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 | | ||
129 | SNDRV_PCM_RATE_64000); | ||
130 | runtime->hw.rate_min = 44100; | ||
131 | break; | ||
132 | case PCM_MULTICH: | ||
133 | runtime->hw.channels_max = chip->model->dac_channels; | ||
134 | break; | ||
135 | } | ||
136 | if (chip->model->pcm_hardware_filter) | ||
137 | chip->model->pcm_hardware_filter(channel, &runtime->hw); | ||
138 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
139 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
140 | if (err < 0) | ||
141 | return err; | ||
142 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
143 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
144 | if (err < 0) | ||
145 | return err; | ||
146 | if (runtime->hw.formats & SNDRV_PCM_FMTBIT_S32_LE) { | ||
147 | err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | ||
148 | if (err < 0) | ||
149 | return err; | ||
150 | } | ||
151 | if (runtime->hw.channels_max > 2) { | ||
152 | err = snd_pcm_hw_constraint_step(runtime, 0, | ||
153 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
154 | 2); | ||
155 | if (err < 0) | ||
156 | return err; | ||
157 | } | ||
158 | snd_pcm_set_sync(substream); | ||
159 | chip->streams[channel] = substream; | ||
160 | |||
161 | mutex_lock(&chip->mutex); | ||
162 | chip->pcm_active |= 1 << channel; | ||
163 | if (channel == PCM_SPDIF) { | ||
164 | chip->spdif_pcm_bits = chip->spdif_bits; | ||
165 | chip->controls[CONTROL_SPDIF_PCM]->vd[0].access &= | ||
166 | ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
167 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
168 | SNDRV_CTL_EVENT_MASK_INFO, | ||
169 | &chip->controls[CONTROL_SPDIF_PCM]->id); | ||
170 | } | ||
171 | mutex_unlock(&chip->mutex); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int oxygen_rec_a_open(struct snd_pcm_substream *substream) | ||
177 | { | ||
178 | return oxygen_open(substream, PCM_A); | ||
179 | } | ||
180 | |||
181 | static int oxygen_rec_b_open(struct snd_pcm_substream *substream) | ||
182 | { | ||
183 | return oxygen_open(substream, PCM_B); | ||
184 | } | ||
185 | |||
186 | static int oxygen_rec_c_open(struct snd_pcm_substream *substream) | ||
187 | { | ||
188 | return oxygen_open(substream, PCM_C); | ||
189 | } | ||
190 | |||
191 | static int oxygen_spdif_open(struct snd_pcm_substream *substream) | ||
192 | { | ||
193 | return oxygen_open(substream, PCM_SPDIF); | ||
194 | } | ||
195 | |||
196 | static int oxygen_multich_open(struct snd_pcm_substream *substream) | ||
197 | { | ||
198 | return oxygen_open(substream, PCM_MULTICH); | ||
199 | } | ||
200 | |||
201 | static int oxygen_ac97_open(struct snd_pcm_substream *substream) | ||
202 | { | ||
203 | return oxygen_open(substream, PCM_AC97); | ||
204 | } | ||
205 | |||
206 | static int oxygen_close(struct snd_pcm_substream *substream) | ||
207 | { | ||
208 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
209 | unsigned int channel = oxygen_substream_channel(substream); | ||
210 | |||
211 | mutex_lock(&chip->mutex); | ||
212 | chip->pcm_active &= ~(1 << channel); | ||
213 | if (channel == PCM_SPDIF) { | ||
214 | chip->controls[CONTROL_SPDIF_PCM]->vd[0].access |= | ||
215 | SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
216 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
217 | SNDRV_CTL_EVENT_MASK_INFO, | ||
218 | &chip->controls[CONTROL_SPDIF_PCM]->id); | ||
219 | } | ||
220 | if (channel == PCM_SPDIF || channel == PCM_MULTICH) | ||
221 | oxygen_update_spdif_source(chip); | ||
222 | mutex_unlock(&chip->mutex); | ||
223 | |||
224 | chip->streams[channel] = NULL; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static unsigned int oxygen_format(struct snd_pcm_hw_params *hw_params) | ||
229 | { | ||
230 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | ||
231 | return OXYGEN_FORMAT_24; | ||
232 | else | ||
233 | return OXYGEN_FORMAT_16; | ||
234 | } | ||
235 | |||
236 | static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) | ||
237 | { | ||
238 | switch (params_rate(hw_params)) { | ||
239 | case 32000: | ||
240 | return OXYGEN_RATE_32000; | ||
241 | case 44100: | ||
242 | return OXYGEN_RATE_44100; | ||
243 | default: /* 48000 */ | ||
244 | return OXYGEN_RATE_48000; | ||
245 | case 64000: | ||
246 | return OXYGEN_RATE_64000; | ||
247 | case 88200: | ||
248 | return OXYGEN_RATE_88200; | ||
249 | case 96000: | ||
250 | return OXYGEN_RATE_96000; | ||
251 | case 176400: | ||
252 | return OXYGEN_RATE_176400; | ||
253 | case 192000: | ||
254 | return OXYGEN_RATE_192000; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params) | ||
259 | { | ||
260 | if (params_rate(hw_params) <= 96000) | ||
261 | return OXYGEN_I2S_MCLK_256; | ||
262 | else | ||
263 | return OXYGEN_I2S_MCLK_128; | ||
264 | } | ||
265 | |||
266 | static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) | ||
267 | { | ||
268 | if (params_format(hw_params) == SNDRV_PCM_FORMAT_S32_LE) | ||
269 | return OXYGEN_I2S_BITS_24; | ||
270 | else | ||
271 | return OXYGEN_I2S_BITS_16; | ||
272 | } | ||
273 | |||
274 | static unsigned int oxygen_play_channels(struct snd_pcm_hw_params *hw_params) | ||
275 | { | ||
276 | switch (params_channels(hw_params)) { | ||
277 | default: /* 2 */ | ||
278 | return OXYGEN_PLAY_CHANNELS_2; | ||
279 | case 4: | ||
280 | return OXYGEN_PLAY_CHANNELS_4; | ||
281 | case 6: | ||
282 | return OXYGEN_PLAY_CHANNELS_6; | ||
283 | case 8: | ||
284 | return OXYGEN_PLAY_CHANNELS_8; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static const unsigned int channel_base_registers[PCM_COUNT] = { | ||
289 | [PCM_A] = OXYGEN_DMA_A_ADDRESS, | ||
290 | [PCM_B] = OXYGEN_DMA_B_ADDRESS, | ||
291 | [PCM_C] = OXYGEN_DMA_C_ADDRESS, | ||
292 | [PCM_SPDIF] = OXYGEN_DMA_SPDIF_ADDRESS, | ||
293 | [PCM_MULTICH] = OXYGEN_DMA_MULTICH_ADDRESS, | ||
294 | [PCM_AC97] = OXYGEN_DMA_AC97_ADDRESS, | ||
295 | }; | ||
296 | |||
297 | static int oxygen_hw_params(struct snd_pcm_substream *substream, | ||
298 | struct snd_pcm_hw_params *hw_params) | ||
299 | { | ||
300 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
301 | unsigned int channel = oxygen_substream_channel(substream); | ||
302 | int err; | ||
303 | |||
304 | err = snd_pcm_lib_malloc_pages(substream, | ||
305 | params_buffer_bytes(hw_params)); | ||
306 | if (err < 0) | ||
307 | return err; | ||
308 | |||
309 | oxygen_write32(chip, channel_base_registers[channel], | ||
310 | (u32)substream->runtime->dma_addr); | ||
311 | if (channel == PCM_MULTICH) { | ||
312 | oxygen_write32(chip, OXYGEN_DMA_MULTICH_COUNT, | ||
313 | params_buffer_bytes(hw_params) / 4 - 1); | ||
314 | oxygen_write32(chip, OXYGEN_DMA_MULTICH_TCOUNT, | ||
315 | params_period_bytes(hw_params) / 4 - 1); | ||
316 | } else { | ||
317 | oxygen_write16(chip, channel_base_registers[channel] + 4, | ||
318 | params_buffer_bytes(hw_params) / 4 - 1); | ||
319 | oxygen_write16(chip, channel_base_registers[channel] + 6, | ||
320 | params_period_bytes(hw_params) / 4 - 1); | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, | ||
326 | struct snd_pcm_hw_params *hw_params) | ||
327 | { | ||
328 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
329 | int err; | ||
330 | |||
331 | err = oxygen_hw_params(substream, hw_params); | ||
332 | if (err < 0) | ||
333 | return err; | ||
334 | |||
335 | spin_lock_irq(&chip->reg_lock); | ||
336 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
337 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_A_SHIFT, | ||
338 | OXYGEN_REC_FORMAT_A_MASK); | ||
339 | oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, | ||
340 | oxygen_rate(hw_params) | | ||
341 | oxygen_i2s_mclk(hw_params) | | ||
342 | chip->model->adc_i2s_format | | ||
343 | oxygen_i2s_bits(hw_params), | ||
344 | OXYGEN_I2S_RATE_MASK | | ||
345 | OXYGEN_I2S_FORMAT_MASK | | ||
346 | OXYGEN_I2S_MCLK_MASK | | ||
347 | OXYGEN_I2S_BITS_MASK); | ||
348 | spin_unlock_irq(&chip->reg_lock); | ||
349 | |||
350 | mutex_lock(&chip->mutex); | ||
351 | chip->model->set_adc_params(chip, hw_params); | ||
352 | mutex_unlock(&chip->mutex); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, | ||
357 | struct snd_pcm_hw_params *hw_params) | ||
358 | { | ||
359 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
360 | int is_ac97; | ||
361 | int err; | ||
362 | |||
363 | err = oxygen_hw_params(substream, hw_params); | ||
364 | if (err < 0) | ||
365 | return err; | ||
366 | |||
367 | is_ac97 = chip->has_ac97_1 && | ||
368 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97); | ||
369 | |||
370 | spin_lock_irq(&chip->reg_lock); | ||
371 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
372 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_B_SHIFT, | ||
373 | OXYGEN_REC_FORMAT_B_MASK); | ||
374 | if (!is_ac97) | ||
375 | oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, | ||
376 | oxygen_rate(hw_params) | | ||
377 | oxygen_i2s_mclk(hw_params) | | ||
378 | chip->model->adc_i2s_format | | ||
379 | oxygen_i2s_bits(hw_params), | ||
380 | OXYGEN_I2S_RATE_MASK | | ||
381 | OXYGEN_I2S_FORMAT_MASK | | ||
382 | OXYGEN_I2S_MCLK_MASK | | ||
383 | OXYGEN_I2S_BITS_MASK); | ||
384 | spin_unlock_irq(&chip->reg_lock); | ||
385 | |||
386 | if (!is_ac97) { | ||
387 | mutex_lock(&chip->mutex); | ||
388 | chip->model->set_adc_params(chip, hw_params); | ||
389 | mutex_unlock(&chip->mutex); | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream, | ||
395 | struct snd_pcm_hw_params *hw_params) | ||
396 | { | ||
397 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
398 | int err; | ||
399 | |||
400 | err = oxygen_hw_params(substream, hw_params); | ||
401 | if (err < 0) | ||
402 | return err; | ||
403 | |||
404 | spin_lock_irq(&chip->reg_lock); | ||
405 | oxygen_write8_masked(chip, OXYGEN_REC_FORMAT, | ||
406 | oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT, | ||
407 | OXYGEN_REC_FORMAT_C_MASK); | ||
408 | spin_unlock_irq(&chip->reg_lock); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, | ||
413 | struct snd_pcm_hw_params *hw_params) | ||
414 | { | ||
415 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
416 | int err; | ||
417 | |||
418 | err = oxygen_hw_params(substream, hw_params); | ||
419 | if (err < 0) | ||
420 | return err; | ||
421 | |||
422 | spin_lock_irq(&chip->reg_lock); | ||
423 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | ||
424 | OXYGEN_SPDIF_OUT_ENABLE); | ||
425 | oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, | ||
426 | oxygen_format(hw_params) << OXYGEN_SPDIF_FORMAT_SHIFT, | ||
427 | OXYGEN_SPDIF_FORMAT_MASK); | ||
428 | oxygen_write32_masked(chip, OXYGEN_SPDIF_CONTROL, | ||
429 | oxygen_rate(hw_params) << OXYGEN_SPDIF_OUT_RATE_SHIFT, | ||
430 | OXYGEN_SPDIF_OUT_RATE_MASK); | ||
431 | oxygen_update_spdif_source(chip); | ||
432 | spin_unlock_irq(&chip->reg_lock); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, | ||
437 | struct snd_pcm_hw_params *hw_params) | ||
438 | { | ||
439 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
440 | int err; | ||
441 | |||
442 | err = oxygen_hw_params(substream, hw_params); | ||
443 | if (err < 0) | ||
444 | return err; | ||
445 | |||
446 | spin_lock_irq(&chip->reg_lock); | ||
447 | oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, | ||
448 | oxygen_play_channels(hw_params), | ||
449 | OXYGEN_PLAY_CHANNELS_MASK); | ||
450 | oxygen_write8_masked(chip, OXYGEN_PLAY_FORMAT, | ||
451 | oxygen_format(hw_params) << OXYGEN_MULTICH_FORMAT_SHIFT, | ||
452 | OXYGEN_MULTICH_FORMAT_MASK); | ||
453 | oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, | ||
454 | oxygen_rate(hw_params) | | ||
455 | chip->model->dac_i2s_format | | ||
456 | oxygen_i2s_bits(hw_params), | ||
457 | OXYGEN_I2S_RATE_MASK | | ||
458 | OXYGEN_I2S_FORMAT_MASK | | ||
459 | OXYGEN_I2S_BITS_MASK); | ||
460 | oxygen_update_dac_routing(chip); | ||
461 | oxygen_update_spdif_source(chip); | ||
462 | spin_unlock_irq(&chip->reg_lock); | ||
463 | |||
464 | mutex_lock(&chip->mutex); | ||
465 | chip->model->set_dac_params(chip, hw_params); | ||
466 | mutex_unlock(&chip->mutex); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int oxygen_hw_free(struct snd_pcm_substream *substream) | ||
471 | { | ||
472 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
473 | unsigned int channel = oxygen_substream_channel(substream); | ||
474 | |||
475 | spin_lock_irq(&chip->reg_lock); | ||
476 | chip->interrupt_mask &= ~(1 << channel); | ||
477 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
478 | spin_unlock_irq(&chip->reg_lock); | ||
479 | |||
480 | return snd_pcm_lib_free_pages(substream); | ||
481 | } | ||
482 | |||
483 | static int oxygen_spdif_hw_free(struct snd_pcm_substream *substream) | ||
484 | { | ||
485 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
486 | |||
487 | spin_lock_irq(&chip->reg_lock); | ||
488 | oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, | ||
489 | OXYGEN_SPDIF_OUT_ENABLE); | ||
490 | spin_unlock_irq(&chip->reg_lock); | ||
491 | return oxygen_hw_free(substream); | ||
492 | } | ||
493 | |||
494 | static int oxygen_prepare(struct snd_pcm_substream *substream) | ||
495 | { | ||
496 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
497 | unsigned int channel = oxygen_substream_channel(substream); | ||
498 | unsigned int channel_mask = 1 << channel; | ||
499 | |||
500 | spin_lock_irq(&chip->reg_lock); | ||
501 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
502 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
503 | |||
504 | chip->interrupt_mask |= channel_mask; | ||
505 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | ||
506 | spin_unlock_irq(&chip->reg_lock); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int oxygen_trigger(struct snd_pcm_substream *substream, int cmd) | ||
511 | { | ||
512 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
513 | struct snd_pcm_substream *s; | ||
514 | unsigned int mask = 0; | ||
515 | int pausing; | ||
516 | |||
517 | switch (cmd) { | ||
518 | case SNDRV_PCM_TRIGGER_STOP: | ||
519 | case SNDRV_PCM_TRIGGER_START: | ||
520 | pausing = 0; | ||
521 | break; | ||
522 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
523 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
524 | pausing = 1; | ||
525 | break; | ||
526 | default: | ||
527 | return -EINVAL; | ||
528 | } | ||
529 | |||
530 | snd_pcm_group_for_each_entry(s, substream) { | ||
531 | if (snd_pcm_substream_chip(s) == chip) { | ||
532 | mask |= 1 << oxygen_substream_channel(s); | ||
533 | snd_pcm_trigger_done(s, substream); | ||
534 | } | ||
535 | } | ||
536 | |||
537 | spin_lock(&chip->reg_lock); | ||
538 | if (!pausing) { | ||
539 | if (cmd == SNDRV_PCM_TRIGGER_START) | ||
540 | chip->pcm_running |= mask; | ||
541 | else | ||
542 | chip->pcm_running &= ~mask; | ||
543 | oxygen_write8(chip, OXYGEN_DMA_STATUS, chip->pcm_running); | ||
544 | } else { | ||
545 | if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) | ||
546 | oxygen_set_bits8(chip, OXYGEN_DMA_PAUSE, mask); | ||
547 | else | ||
548 | oxygen_clear_bits8(chip, OXYGEN_DMA_PAUSE, mask); | ||
549 | } | ||
550 | spin_unlock(&chip->reg_lock); | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static snd_pcm_uframes_t oxygen_pointer(struct snd_pcm_substream *substream) | ||
555 | { | ||
556 | struct oxygen *chip = snd_pcm_substream_chip(substream); | ||
557 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
558 | unsigned int channel = oxygen_substream_channel(substream); | ||
559 | u32 curr_addr; | ||
560 | |||
561 | /* no spinlock, this read should be atomic */ | ||
562 | curr_addr = oxygen_read32(chip, channel_base_registers[channel]); | ||
563 | return bytes_to_frames(runtime, curr_addr - (u32)runtime->dma_addr); | ||
564 | } | ||
565 | |||
566 | static struct snd_pcm_ops oxygen_rec_a_ops = { | ||
567 | .open = oxygen_rec_a_open, | ||
568 | .close = oxygen_close, | ||
569 | .ioctl = snd_pcm_lib_ioctl, | ||
570 | .hw_params = oxygen_rec_a_hw_params, | ||
571 | .hw_free = oxygen_hw_free, | ||
572 | .prepare = oxygen_prepare, | ||
573 | .trigger = oxygen_trigger, | ||
574 | .pointer = oxygen_pointer, | ||
575 | }; | ||
576 | |||
577 | static struct snd_pcm_ops oxygen_rec_b_ops = { | ||
578 | .open = oxygen_rec_b_open, | ||
579 | .close = oxygen_close, | ||
580 | .ioctl = snd_pcm_lib_ioctl, | ||
581 | .hw_params = oxygen_rec_b_hw_params, | ||
582 | .hw_free = oxygen_hw_free, | ||
583 | .prepare = oxygen_prepare, | ||
584 | .trigger = oxygen_trigger, | ||
585 | .pointer = oxygen_pointer, | ||
586 | }; | ||
587 | |||
588 | static struct snd_pcm_ops oxygen_rec_c_ops = { | ||
589 | .open = oxygen_rec_c_open, | ||
590 | .close = oxygen_close, | ||
591 | .ioctl = snd_pcm_lib_ioctl, | ||
592 | .hw_params = oxygen_rec_c_hw_params, | ||
593 | .hw_free = oxygen_hw_free, | ||
594 | .prepare = oxygen_prepare, | ||
595 | .trigger = oxygen_trigger, | ||
596 | .pointer = oxygen_pointer, | ||
597 | }; | ||
598 | |||
599 | static struct snd_pcm_ops oxygen_spdif_ops = { | ||
600 | .open = oxygen_spdif_open, | ||
601 | .close = oxygen_close, | ||
602 | .ioctl = snd_pcm_lib_ioctl, | ||
603 | .hw_params = oxygen_spdif_hw_params, | ||
604 | .hw_free = oxygen_spdif_hw_free, | ||
605 | .prepare = oxygen_prepare, | ||
606 | .trigger = oxygen_trigger, | ||
607 | .pointer = oxygen_pointer, | ||
608 | }; | ||
609 | |||
610 | static struct snd_pcm_ops oxygen_multich_ops = { | ||
611 | .open = oxygen_multich_open, | ||
612 | .close = oxygen_close, | ||
613 | .ioctl = snd_pcm_lib_ioctl, | ||
614 | .hw_params = oxygen_multich_hw_params, | ||
615 | .hw_free = oxygen_hw_free, | ||
616 | .prepare = oxygen_prepare, | ||
617 | .trigger = oxygen_trigger, | ||
618 | .pointer = oxygen_pointer, | ||
619 | }; | ||
620 | |||
621 | static struct snd_pcm_ops oxygen_ac97_ops = { | ||
622 | .open = oxygen_ac97_open, | ||
623 | .close = oxygen_close, | ||
624 | .ioctl = snd_pcm_lib_ioctl, | ||
625 | .hw_params = oxygen_hw_params, | ||
626 | .hw_free = oxygen_hw_free, | ||
627 | .prepare = oxygen_prepare, | ||
628 | .trigger = oxygen_trigger, | ||
629 | .pointer = oxygen_pointer, | ||
630 | }; | ||
631 | |||
632 | static void oxygen_pcm_free(struct snd_pcm *pcm) | ||
633 | { | ||
634 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
635 | } | ||
636 | |||
637 | int __devinit oxygen_pcm_init(struct oxygen *chip) | ||
638 | { | ||
639 | struct snd_pcm *pcm; | ||
640 | int outs, ins; | ||
641 | int err; | ||
642 | |||
643 | outs = 1; /* OXYGEN_CHANNEL_MULTICH is always used */ | ||
644 | ins = !!(chip->model->used_channels & (OXYGEN_CHANNEL_A | | ||
645 | OXYGEN_CHANNEL_B)); | ||
646 | err = snd_pcm_new(chip->card, "Analog", 0, outs, ins, &pcm); | ||
647 | if (err < 0) | ||
648 | return err; | ||
649 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &oxygen_multich_ops); | ||
650 | if (chip->model->used_channels & OXYGEN_CHANNEL_A) | ||
651 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
652 | &oxygen_rec_a_ops); | ||
653 | else if (chip->model->used_channels & OXYGEN_CHANNEL_B) | ||
654 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
655 | &oxygen_rec_b_ops); | ||
656 | pcm->private_data = chip; | ||
657 | pcm->private_free = oxygen_pcm_free; | ||
658 | strcpy(pcm->name, "Analog"); | ||
659 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, | ||
660 | SNDRV_DMA_TYPE_DEV, | ||
661 | snd_dma_pci_data(chip->pci), | ||
662 | 512 * 1024, 2048 * 1024); | ||
663 | if (ins) | ||
664 | snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, | ||
665 | SNDRV_DMA_TYPE_DEV, | ||
666 | snd_dma_pci_data(chip->pci), | ||
667 | 128 * 1024, 256 * 1024); | ||
668 | |||
669 | outs = !!(chip->model->used_channels & OXYGEN_CHANNEL_SPDIF); | ||
670 | ins = !!(chip->model->used_channels & OXYGEN_CHANNEL_C); | ||
671 | if (outs | ins) { | ||
672 | err = snd_pcm_new(chip->card, "Digital", 1, outs, ins, &pcm); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | if (outs) | ||
676 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
677 | &oxygen_spdif_ops); | ||
678 | if (ins) | ||
679 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
680 | &oxygen_rec_c_ops); | ||
681 | pcm->private_data = chip; | ||
682 | pcm->private_free = oxygen_pcm_free; | ||
683 | strcpy(pcm->name, "Digital"); | ||
684 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
685 | snd_dma_pci_data(chip->pci), | ||
686 | 128 * 1024, 256 * 1024); | ||
687 | } | ||
688 | |||
689 | outs = chip->has_ac97_1 && | ||
690 | (chip->model->used_channels & OXYGEN_CHANNEL_AC97); | ||
691 | ins = outs || | ||
692 | (chip->model->used_channels & (OXYGEN_CHANNEL_A | | ||
693 | OXYGEN_CHANNEL_B)) | ||
694 | == (OXYGEN_CHANNEL_A | OXYGEN_CHANNEL_B); | ||
695 | if (outs | ins) { | ||
696 | err = snd_pcm_new(chip->card, outs ? "AC97" : "Analog2", | ||
697 | 2, outs, ins, &pcm); | ||
698 | if (err < 0) | ||
699 | return err; | ||
700 | if (outs) { | ||
701 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
702 | &oxygen_ac97_ops); | ||
703 | oxygen_write8_masked(chip, OXYGEN_REC_ROUTING, | ||
704 | OXYGEN_REC_B_ROUTE_AC97_1, | ||
705 | OXYGEN_REC_B_ROUTE_MASK); | ||
706 | } | ||
707 | if (ins) | ||
708 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
709 | &oxygen_rec_b_ops); | ||
710 | pcm->private_data = chip; | ||
711 | pcm->private_free = oxygen_pcm_free; | ||
712 | strcpy(pcm->name, outs ? "Front Panel" : "Analog 2"); | ||
713 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
714 | snd_dma_pci_data(chip->pci), | ||
715 | 128 * 1024, 256 * 1024); | ||
716 | } | ||
717 | return 0; | ||
718 | } | ||
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h new file mode 100644 index 000000000000..72de159d4567 --- /dev/null +++ b/sound/pci/oxygen/oxygen_regs.h | |||
@@ -0,0 +1,453 @@ | |||
1 | #ifndef OXYGEN_REGS_H_INCLUDED | ||
2 | #define OXYGEN_REGS_H_INCLUDED | ||
3 | |||
4 | /* recording channel A */ | ||
5 | #define OXYGEN_DMA_A_ADDRESS 0x00 /* 32-bit base address */ | ||
6 | #define OXYGEN_DMA_A_COUNT 0x04 /* buffer counter (dwords) */ | ||
7 | #define OXYGEN_DMA_A_TCOUNT 0x06 /* interrupt counter (dwords) */ | ||
8 | |||
9 | /* recording channel B */ | ||
10 | #define OXYGEN_DMA_B_ADDRESS 0x08 | ||
11 | #define OXYGEN_DMA_B_COUNT 0x0c | ||
12 | #define OXYGEN_DMA_B_TCOUNT 0x0e | ||
13 | |||
14 | /* recording channel C */ | ||
15 | #define OXYGEN_DMA_C_ADDRESS 0x10 | ||
16 | #define OXYGEN_DMA_C_COUNT 0x14 | ||
17 | #define OXYGEN_DMA_C_TCOUNT 0x16 | ||
18 | |||
19 | /* SPDIF playback channel */ | ||
20 | #define OXYGEN_DMA_SPDIF_ADDRESS 0x18 | ||
21 | #define OXYGEN_DMA_SPDIF_COUNT 0x1c | ||
22 | #define OXYGEN_DMA_SPDIF_TCOUNT 0x1e | ||
23 | |||
24 | /* multichannel playback channel */ | ||
25 | #define OXYGEN_DMA_MULTICH_ADDRESS 0x20 | ||
26 | #define OXYGEN_DMA_MULTICH_COUNT 0x24 /* 24 bits */ | ||
27 | #define OXYGEN_DMA_MULTICH_TCOUNT 0x28 /* 24 bits */ | ||
28 | |||
29 | /* AC'97 (front panel) playback channel */ | ||
30 | #define OXYGEN_DMA_AC97_ADDRESS 0x30 | ||
31 | #define OXYGEN_DMA_AC97_COUNT 0x34 | ||
32 | #define OXYGEN_DMA_AC97_TCOUNT 0x36 | ||
33 | |||
34 | /* all registers 0x00..0x36 return current position on read */ | ||
35 | |||
36 | #define OXYGEN_DMA_STATUS 0x40 /* 1 = running, 0 = stop */ | ||
37 | #define OXYGEN_CHANNEL_A 0x01 | ||
38 | #define OXYGEN_CHANNEL_B 0x02 | ||
39 | #define OXYGEN_CHANNEL_C 0x04 | ||
40 | #define OXYGEN_CHANNEL_SPDIF 0x08 | ||
41 | #define OXYGEN_CHANNEL_MULTICH 0x10 | ||
42 | #define OXYGEN_CHANNEL_AC97 0x20 | ||
43 | |||
44 | #define OXYGEN_DMA_PAUSE 0x41 /* 1 = pause */ | ||
45 | /* OXYGEN_CHANNEL_* */ | ||
46 | |||
47 | #define OXYGEN_DMA_RESET 0x42 | ||
48 | /* OXYGEN_CHANNEL_* */ | ||
49 | |||
50 | #define OXYGEN_PLAY_CHANNELS 0x43 | ||
51 | #define OXYGEN_PLAY_CHANNELS_MASK 0x03 | ||
52 | #define OXYGEN_PLAY_CHANNELS_2 0x00 | ||
53 | #define OXYGEN_PLAY_CHANNELS_4 0x01 | ||
54 | #define OXYGEN_PLAY_CHANNELS_6 0x02 | ||
55 | #define OXYGEN_PLAY_CHANNELS_8 0x03 | ||
56 | #define OXYGEN_DMA_A_BURST_MASK 0x04 | ||
57 | #define OXYGEN_DMA_A_BURST_8 0x00 /* dwords */ | ||
58 | #define OXYGEN_DMA_A_BURST_16 0x04 | ||
59 | #define OXYGEN_DMA_MULTICH_BURST_MASK 0x08 | ||
60 | #define OXYGEN_DMA_MULTICH_BURST_8 0x00 | ||
61 | #define OXYGEN_DMA_MULTICH_BURST_16 0x08 | ||
62 | |||
63 | #define OXYGEN_INTERRUPT_MASK 0x44 | ||
64 | /* OXYGEN_CHANNEL_* */ | ||
65 | #define OXYGEN_INT_SPDIF_IN_DETECT 0x0100 | ||
66 | #define OXYGEN_INT_MCU 0x0200 | ||
67 | #define OXYGEN_INT_2WIRE 0x0400 | ||
68 | #define OXYGEN_INT_GPIO 0x0800 | ||
69 | #define OXYGEN_INT_MCB 0x2000 | ||
70 | #define OXYGEN_INT_AC97 0x4000 | ||
71 | |||
72 | #define OXYGEN_INTERRUPT_STATUS 0x46 | ||
73 | /* OXYGEN_CHANNEL_* amd OXYGEN_INT_* */ | ||
74 | #define OXYGEN_INT_MIDI 0x1000 | ||
75 | |||
76 | #define OXYGEN_MISC 0x48 | ||
77 | #define OXYGEN_MISC_WRITE_PCI_SUBID 0x01 | ||
78 | #define OXYGEN_MISC_LATENCY_3F 0x02 | ||
79 | #define OXYGEN_MISC_REC_C_FROM_SPDIF 0x04 | ||
80 | #define OXYGEN_MISC_REC_B_FROM_AC97 0x08 | ||
81 | #define OXYGEN_MISC_REC_A_FROM_MULTICH 0x10 | ||
82 | #define OXYGEN_MISC_PCI_MEM_W_1_CLOCK 0x20 | ||
83 | #define OXYGEN_MISC_MIDI 0x40 | ||
84 | #define OXYGEN_MISC_CRYSTAL_MASK 0x80 | ||
85 | #define OXYGEN_MISC_CRYSTAL_24576 0x00 | ||
86 | #define OXYGEN_MISC_CRYSTAL_27 0x80 /* MHz */ | ||
87 | |||
88 | #define OXYGEN_REC_FORMAT 0x4a | ||
89 | #define OXYGEN_REC_FORMAT_A_MASK 0x03 | ||
90 | #define OXYGEN_REC_FORMAT_A_SHIFT 0 | ||
91 | #define OXYGEN_REC_FORMAT_B_MASK 0x0c | ||
92 | #define OXYGEN_REC_FORMAT_B_SHIFT 2 | ||
93 | #define OXYGEN_REC_FORMAT_C_MASK 0x30 | ||
94 | #define OXYGEN_REC_FORMAT_C_SHIFT 4 | ||
95 | #define OXYGEN_FORMAT_16 0x00 | ||
96 | #define OXYGEN_FORMAT_24 0x01 | ||
97 | #define OXYGEN_FORMAT_32 0x02 | ||
98 | |||
99 | #define OXYGEN_PLAY_FORMAT 0x4b | ||
100 | #define OXYGEN_SPDIF_FORMAT_MASK 0x03 | ||
101 | #define OXYGEN_SPDIF_FORMAT_SHIFT 0 | ||
102 | #define OXYGEN_MULTICH_FORMAT_MASK 0x0c | ||
103 | #define OXYGEN_MULTICH_FORMAT_SHIFT 2 | ||
104 | /* OXYGEN_FORMAT_* */ | ||
105 | |||
106 | #define OXYGEN_REC_CHANNELS 0x4c | ||
107 | #define OXYGEN_REC_CHANNELS_MASK 0x07 | ||
108 | #define OXYGEN_REC_CHANNELS_2_2_2 0x00 /* DMA A, B, C */ | ||
109 | #define OXYGEN_REC_CHANNELS_4_2_2 0x01 | ||
110 | #define OXYGEN_REC_CHANNELS_6_0_2 0x02 | ||
111 | #define OXYGEN_REC_CHANNELS_6_2_0 0x03 | ||
112 | #define OXYGEN_REC_CHANNELS_8_0_0 0x04 | ||
113 | |||
114 | #define OXYGEN_FUNCTION 0x50 | ||
115 | #define OXYGEN_FUNCTION_CLOCK_MASK 0x01 | ||
116 | #define OXYGEN_FUNCTION_CLOCK_PLL 0x00 | ||
117 | #define OXYGEN_FUNCTION_CLOCK_CRYSTAL 0x01 | ||
118 | #define OXYGEN_FUNCTION_RESET_CODEC 0x02 | ||
119 | #define OXYGEN_FUNCTION_RESET_POL 0x04 | ||
120 | #define OXYGEN_FUNCTION_PWDN 0x08 | ||
121 | #define OXYGEN_FUNCTION_PWDN_EN 0x10 | ||
122 | #define OXYGEN_FUNCTION_PWDN_POL 0x20 | ||
123 | #define OXYGEN_FUNCTION_2WIRE_SPI_MASK 0x40 | ||
124 | #define OXYGEN_FUNCTION_SPI 0x00 | ||
125 | #define OXYGEN_FUNCTION_2WIRE 0x40 | ||
126 | #define OXYGEN_FUNCTION_ENABLE_SPI_4_5 0x80 /* 0 = EEPROM */ | ||
127 | |||
128 | #define OXYGEN_I2S_MULTICH_FORMAT 0x60 | ||
129 | #define OXYGEN_I2S_RATE_MASK 0x0007 /* LRCK */ | ||
130 | #define OXYGEN_RATE_32000 0x0000 | ||
131 | #define OXYGEN_RATE_44100 0x0001 | ||
132 | #define OXYGEN_RATE_48000 0x0002 | ||
133 | #define OXYGEN_RATE_64000 0x0003 | ||
134 | #define OXYGEN_RATE_88200 0x0004 | ||
135 | #define OXYGEN_RATE_96000 0x0005 | ||
136 | #define OXYGEN_RATE_176400 0x0006 | ||
137 | #define OXYGEN_RATE_192000 0x0007 | ||
138 | #define OXYGEN_I2S_FORMAT_MASK 0x0008 | ||
139 | #define OXYGEN_I2S_FORMAT_I2S 0x0000 | ||
140 | #define OXYGEN_I2S_FORMAT_LJUST 0x0008 | ||
141 | #define OXYGEN_I2S_MCLK_MASK 0x0030 /* MCLK/LRCK */ | ||
142 | #define OXYGEN_I2S_MCLK_128 0x0000 | ||
143 | #define OXYGEN_I2S_MCLK_256 0x0010 | ||
144 | #define OXYGEN_I2S_MCLK_512 0x0020 | ||
145 | #define OXYGEN_I2S_BITS_MASK 0x00c0 | ||
146 | #define OXYGEN_I2S_BITS_16 0x0000 | ||
147 | #define OXYGEN_I2S_BITS_20 0x0040 | ||
148 | #define OXYGEN_I2S_BITS_24 0x0080 | ||
149 | #define OXYGEN_I2S_BITS_32 0x00c0 | ||
150 | #define OXYGEN_I2S_MASTER 0x0100 | ||
151 | #define OXYGEN_I2S_BCLK_MASK 0x0600 /* BCLK/LRCK */ | ||
152 | #define OXYGEN_I2S_BCLK_64 0x0000 | ||
153 | #define OXYGEN_I2S_BCLK_128 0x0200 | ||
154 | #define OXYGEN_I2S_BCLK_256 0x0400 | ||
155 | #define OXYGEN_I2S_MUTE_MCLK 0x0800 | ||
156 | |||
157 | #define OXYGEN_I2S_A_FORMAT 0x62 | ||
158 | #define OXYGEN_I2S_B_FORMAT 0x64 | ||
159 | #define OXYGEN_I2S_C_FORMAT 0x66 | ||
160 | /* like OXYGEN_I2S_MULTICH_FORMAT */ | ||
161 | |||
162 | #define OXYGEN_SPDIF_CONTROL 0x70 | ||
163 | #define OXYGEN_SPDIF_OUT_ENABLE 0x00000002 | ||
164 | #define OXYGEN_SPDIF_LOOPBACK 0x00000004 /* in to out */ | ||
165 | #define OXYGEN_SPDIF_SENSE_MASK 0x00000008 | ||
166 | #define OXYGEN_SPDIF_LOCK_MASK 0x00000010 | ||
167 | #define OXYGEN_SPDIF_RATE_MASK 0x00000020 | ||
168 | #define OXYGEN_SPDIF_SPDVALID 0x00000040 | ||
169 | #define OXYGEN_SPDIF_SENSE_PAR 0x00000200 | ||
170 | #define OXYGEN_SPDIF_LOCK_PAR 0x00000400 | ||
171 | #define OXYGEN_SPDIF_SENSE_STATUS 0x00000800 | ||
172 | #define OXYGEN_SPDIF_LOCK_STATUS 0x00001000 | ||
173 | #define OXYGEN_SPDIF_SENSE_INT 0x00002000 /* r/wc */ | ||
174 | #define OXYGEN_SPDIF_LOCK_INT 0x00004000 /* r/wc */ | ||
175 | #define OXYGEN_SPDIF_RATE_INT 0x00008000 /* r/wc */ | ||
176 | #define OXYGEN_SPDIF_IN_CLOCK_MASK 0x00010000 | ||
177 | #define OXYGEN_SPDIF_IN_CLOCK_96 0x00000000 /* <= 96 kHz */ | ||
178 | #define OXYGEN_SPDIF_IN_CLOCK_192 0x00010000 /* > 96 kHz */ | ||
179 | #define OXYGEN_SPDIF_OUT_RATE_MASK 0x07000000 | ||
180 | #define OXYGEN_SPDIF_OUT_RATE_SHIFT 24 | ||
181 | /* OXYGEN_RATE_* << OXYGEN_SPDIF_OUT_RATE_SHIFT */ | ||
182 | |||
183 | #define OXYGEN_SPDIF_OUTPUT_BITS 0x74 | ||
184 | #define OXYGEN_SPDIF_NONAUDIO 0x00000002 | ||
185 | #define OXYGEN_SPDIF_C 0x00000004 | ||
186 | #define OXYGEN_SPDIF_PREEMPHASIS 0x00000008 | ||
187 | #define OXYGEN_SPDIF_CATEGORY_MASK 0x000007f0 | ||
188 | #define OXYGEN_SPDIF_CATEGORY_SHIFT 4 | ||
189 | #define OXYGEN_SPDIF_ORIGINAL 0x00000800 | ||
190 | #define OXYGEN_SPDIF_CS_RATE_MASK 0x0000f000 | ||
191 | #define OXYGEN_SPDIF_CS_RATE_SHIFT 12 | ||
192 | #define OXYGEN_SPDIF_V 0x00010000 /* 0 = valid */ | ||
193 | |||
194 | #define OXYGEN_SPDIF_INPUT_BITS 0x78 | ||
195 | /* 32 bits, IEC958_AES_* */ | ||
196 | |||
197 | #define OXYGEN_EEPROM_CONTROL 0x80 | ||
198 | #define OXYGEN_EEPROM_ADDRESS_MASK 0x7f | ||
199 | #define OXYGEN_EEPROM_DIR_MASK 0x80 | ||
200 | #define OXYGEN_EEPROM_DIR_READ 0x00 | ||
201 | #define OXYGEN_EEPROM_DIR_WRITE 0x80 | ||
202 | |||
203 | #define OXYGEN_EEPROM_STATUS 0x81 | ||
204 | #define OXYGEN_EEPROM_VALID 0x40 | ||
205 | #define OXYGEN_EEPROM_BUSY 0x80 | ||
206 | |||
207 | #define OXYGEN_EEPROM_DATA 0x82 /* 16 bits */ | ||
208 | |||
209 | #define OXYGEN_2WIRE_CONTROL 0x90 | ||
210 | #define OXYGEN_2WIRE_DIR_MASK 0x01 | ||
211 | #define OXYGEN_2WIRE_DIR_WRITE 0x00 | ||
212 | #define OXYGEN_2WIRE_DIR_READ 0x01 | ||
213 | #define OXYGEN_2WIRE_ADDRESS_MASK 0xfe /* slave device address */ | ||
214 | #define OXYGEN_2WIRE_ADDRESS_SHIFT 1 | ||
215 | |||
216 | #define OXYGEN_2WIRE_MAP 0x91 /* address, 8 bits */ | ||
217 | #define OXYGEN_2WIRE_DATA 0x92 /* data, 16 bits */ | ||
218 | |||
219 | #define OXYGEN_2WIRE_BUS_STATUS 0x94 | ||
220 | #define OXYGEN_2WIRE_BUSY 0x0001 | ||
221 | #define OXYGEN_2WIRE_LENGTH_MASK 0x0002 | ||
222 | #define OXYGEN_2WIRE_LENGTH_8 0x0000 | ||
223 | #define OXYGEN_2WIRE_LENGTH_16 0x0002 | ||
224 | #define OXYGEN_2WIRE_MANUAL_READ 0x0004 /* 0 = auto read */ | ||
225 | #define OXYGEN_2WIRE_WRITE_MAP_ONLY 0x0008 | ||
226 | #define OXYGEN_2WIRE_SLAVE_AD_MASK 0x0030 /* AD0, AD1 */ | ||
227 | #define OXYGEN_2WIRE_INTERRUPT_MASK 0x0040 /* 0 = int. if not responding */ | ||
228 | #define OXYGEN_2WIRE_SLAVE_NO_RESPONSE 0x0080 | ||
229 | #define OXYGEN_2WIRE_SPEED_MASK 0x0100 | ||
230 | #define OXYGEN_2WIRE_SPEED_STANDARD 0x0000 | ||
231 | #define OXYGEN_2WIRE_SPEED_FAST 0x0100 | ||
232 | #define OXYGEN_2WIRE_CLOCK_SYNC 0x0200 | ||
233 | #define OXYGEN_2WIRE_BUS_RESET 0x0400 | ||
234 | |||
235 | #define OXYGEN_SPI_CONTROL 0x98 | ||
236 | #define OXYGEN_SPI_BUSY 0x01 /* read */ | ||
237 | #define OXYGEN_SPI_TRIGGER 0x01 /* write */ | ||
238 | #define OXYGEN_SPI_DATA_LENGTH_MASK 0x02 | ||
239 | #define OXYGEN_SPI_DATA_LENGTH_2 0x00 | ||
240 | #define OXYGEN_SPI_DATA_LENGTH_3 0x02 | ||
241 | #define OXYGEN_SPI_CLOCK_MASK 0xc0 | ||
242 | #define OXYGEN_SPI_CLOCK_160 0x00 /* ns */ | ||
243 | #define OXYGEN_SPI_CLOCK_320 0x40 | ||
244 | #define OXYGEN_SPI_CLOCK_640 0x80 | ||
245 | #define OXYGEN_SPI_CLOCK_1280 0xc0 | ||
246 | #define OXYGEN_SPI_CODEC_MASK 0x70 /* 0..5 */ | ||
247 | #define OXYGEN_SPI_CODEC_SHIFT 4 | ||
248 | #define OXYGEN_SPI_CEN_MASK 0x80 | ||
249 | #define OXYGEN_SPI_CEN_LATCH_CLOCK_LO 0x00 | ||
250 | #define OXYGEN_SPI_CEN_LATCH_CLOCK_HI 0x80 | ||
251 | |||
252 | #define OXYGEN_SPI_DATA1 0x99 | ||
253 | #define OXYGEN_SPI_DATA2 0x9a | ||
254 | #define OXYGEN_SPI_DATA3 0x9b | ||
255 | |||
256 | #define OXYGEN_MPU401 0xa0 | ||
257 | |||
258 | #define OXYGEN_MPU401_CONTROL 0xa2 | ||
259 | #define OXYGEN_MPU401_LOOPBACK 0x01 /* TXD to RXD */ | ||
260 | |||
261 | #define OXYGEN_GPI_DATA 0xa4 | ||
262 | /* bits 0..5 = pin XGPI0..XGPI5 */ | ||
263 | |||
264 | #define OXYGEN_GPI_INTERRUPT_MASK 0xa5 | ||
265 | /* bits 0..5, 1 = enable */ | ||
266 | |||
267 | #define OXYGEN_GPIO_DATA 0xa6 | ||
268 | /* bits 0..9 */ | ||
269 | |||
270 | #define OXYGEN_GPIO_CONTROL 0xa8 | ||
271 | /* bits 0..9, 0 = input, 1 = output */ | ||
272 | #define OXYGEN_GPIO1_XSLAVE_RDY 0x8000 | ||
273 | |||
274 | #define OXYGEN_GPIO_INTERRUPT_MASK 0xaa | ||
275 | /* bits 0..9, 1 = enable */ | ||
276 | |||
277 | #define OXYGEN_DEVICE_SENSE 0xac | ||
278 | #define OXYGEN_HEAD_PHONE_DETECT 0x01 | ||
279 | #define OXYGEN_HEAD_PHONE_MASK 0x06 | ||
280 | #define OXYGEN_HEAD_PHONE_PASSIVE_SPK 0x00 | ||
281 | #define OXYGEN_HEAD_PHONE_HP 0x02 | ||
282 | #define OXYGEN_HEAD_PHONE_ACTIVE_SPK 0x04 | ||
283 | |||
284 | #define OXYGEN_MCU_2WIRE_DATA 0xb0 | ||
285 | |||
286 | #define OXYGEN_MCU_2WIRE_MAP 0xb2 | ||
287 | |||
288 | #define OXYGEN_MCU_2WIRE_STATUS 0xb3 | ||
289 | #define OXYGEN_MCU_2WIRE_BUSY 0x01 | ||
290 | #define OXYGEN_MCU_2WIRE_LENGTH_MASK 0x06 | ||
291 | #define OXYGEN_MCU_2WIRE_LENGTH_1 0x00 | ||
292 | #define OXYGEN_MCU_2WIRE_LENGTH_2 0x02 | ||
293 | #define OXYGEN_MCU_2WIRE_LENGTH_3 0x04 | ||
294 | #define OXYGEN_MCU_2WIRE_WRITE 0x08 /* r/wc */ | ||
295 | #define OXYGEN_MCU_2WIRE_READ 0x10 /* r/wc */ | ||
296 | #define OXYGEN_MCU_2WIRE_DRV_XACT_FAIL 0x20 /* r/wc */ | ||
297 | #define OXYGEN_MCU_2WIRE_RESET 0x40 | ||
298 | |||
299 | #define OXYGEN_MCU_2WIRE_CONTROL 0xb4 | ||
300 | #define OXYGEN_MCU_2WIRE_DRV_ACK 0x01 | ||
301 | #define OXYGEN_MCU_2WIRE_DRV_XACT 0x02 | ||
302 | #define OXYGEN_MCU_2WIRE_INT_MASK 0x04 | ||
303 | #define OXYGEN_MCU_2WIRE_SYNC_MASK 0x08 | ||
304 | #define OXYGEN_MCU_2WIRE_SYNC_RDY_PIN 0x00 | ||
305 | #define OXYGEN_MCU_2WIRE_SYNC_DATA 0x08 | ||
306 | #define OXYGEN_MCU_2WIRE_ADDRESS_MASK 0x30 | ||
307 | #define OXYGEN_MCU_2WIRE_ADDRESS_10 0x00 | ||
308 | #define OXYGEN_MCU_2WIRE_ADDRESS_12 0x10 | ||
309 | #define OXYGEN_MCU_2WIRE_ADDRESS_14 0x20 | ||
310 | #define OXYGEN_MCU_2WIRE_ADDRESS_16 0x30 | ||
311 | #define OXYGEN_MCU_2WIRE_INT_POL 0x40 | ||
312 | #define OXYGEN_MCU_2WIRE_SYNC_ENABLE 0x80 | ||
313 | |||
314 | #define OXYGEN_PLAY_ROUTING 0xc0 | ||
315 | #define OXYGEN_PLAY_MUTE01 0x0001 | ||
316 | #define OXYGEN_PLAY_MUTE23 0x0002 | ||
317 | #define OXYGEN_PLAY_MUTE45 0x0004 | ||
318 | #define OXYGEN_PLAY_MUTE67 0x0008 | ||
319 | #define OXYGEN_PLAY_MULTICH_MASK 0x0010 | ||
320 | #define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000 | ||
321 | #define OXYGEN_PLAY_MULTICH_AC97 0x0010 | ||
322 | #define OXYGEN_PLAY_SPDIF_MASK 0x00e0 | ||
323 | #define OXYGEN_PLAY_SPDIF_SPDIF 0x0000 | ||
324 | #define OXYGEN_PLAY_SPDIF_MULTICH_01 0x0020 | ||
325 | #define OXYGEN_PLAY_SPDIF_MULTICH_23 0x0040 | ||
326 | #define OXYGEN_PLAY_SPDIF_MULTICH_45 0x0060 | ||
327 | #define OXYGEN_PLAY_SPDIF_MULTICH_67 0x0080 | ||
328 | #define OXYGEN_PLAY_SPDIF_REC_A 0x00a0 | ||
329 | #define OXYGEN_PLAY_SPDIF_REC_B 0x00c0 | ||
330 | #define OXYGEN_PLAY_SPDIF_I2S_ADC_3 0x00e0 | ||
331 | #define OXYGEN_PLAY_DAC0_SOURCE_MASK 0x0300 | ||
332 | #define OXYGEN_PLAY_DAC0_SOURCE_SHIFT 8 | ||
333 | #define OXYGEN_PLAY_DAC1_SOURCE_MASK 0x0c00 | ||
334 | #define OXYGEN_PLAY_DAC1_SOURCE_SHIFT 10 | ||
335 | #define OXYGEN_PLAY_DAC2_SOURCE_MASK 0x3000 | ||
336 | #define OXYGEN_PLAY_DAC2_SOURCE_SHIFT 12 | ||
337 | #define OXYGEN_PLAY_DAC3_SOURCE_MASK 0xc000 | ||
338 | #define OXYGEN_PLAY_DAC3_SOURCE_SHIFT 14 | ||
339 | |||
340 | #define OXYGEN_REC_ROUTING 0xc2 | ||
341 | #define OXYGEN_MUTE_I2S_ADC_1 0x01 | ||
342 | #define OXYGEN_MUTE_I2S_ADC_2 0x02 | ||
343 | #define OXYGEN_MUTE_I2S_ADC_3 0x04 | ||
344 | #define OXYGEN_REC_A_ROUTE_MASK 0x08 | ||
345 | #define OXYGEN_REC_A_ROUTE_I2S_ADC_1 0x00 | ||
346 | #define OXYGEN_REC_A_ROUTE_AC97_0 0x08 | ||
347 | #define OXYGEN_REC_B_ROUTE_MASK 0x10 | ||
348 | #define OXYGEN_REC_B_ROUTE_I2S_ADC_2 0x00 | ||
349 | #define OXYGEN_REC_B_ROUTE_AC97_1 0x10 | ||
350 | #define OXYGEN_REC_C_ROUTE_MASK 0x20 | ||
351 | #define OXYGEN_REC_C_ROUTE_SPDIF 0x00 | ||
352 | #define OXYGEN_REC_C_ROUTE_I2S_ADC_3 0x20 | ||
353 | |||
354 | #define OXYGEN_ADC_MONITOR 0xc3 | ||
355 | #define OXYGEN_ADC_MONITOR_A 0x01 | ||
356 | #define OXYGEN_ADC_MONITOR_A_HALF_VOL 0x02 | ||
357 | #define OXYGEN_ADC_MONITOR_B 0x04 | ||
358 | #define OXYGEN_ADC_MONITOR_B_HALF_VOL 0x08 | ||
359 | #define OXYGEN_ADC_MONITOR_C 0x10 | ||
360 | #define OXYGEN_ADC_MONITOR_C_HALF_VOL 0x20 | ||
361 | |||
362 | #define OXYGEN_A_MONITOR_ROUTING 0xc4 | ||
363 | #define OXYGEN_A_MONITOR_ROUTE_0_MASK 0x03 | ||
364 | #define OXYGEN_A_MONITOR_ROUTE_0_SHIFT 0 | ||
365 | #define OXYGEN_A_MONITOR_ROUTE_1_MASK 0x0c | ||
366 | #define OXYGEN_A_MONITOR_ROUTE_1_SHIFT 2 | ||
367 | #define OXYGEN_A_MONITOR_ROUTE_2_MASK 0x30 | ||
368 | #define OXYGEN_A_MONITOR_ROUTE_2_SHIFT 4 | ||
369 | #define OXYGEN_A_MONITOR_ROUTE_3_MASK 0xc0 | ||
370 | #define OXYGEN_A_MONITOR_ROUTE_3_SHIFT 6 | ||
371 | |||
372 | #define OXYGEN_AC97_CONTROL 0xd0 | ||
373 | #define OXYGEN_AC97_COLD_RESET 0x0001 | ||
374 | #define OXYGEN_AC97_SUSPENDED 0x0002 /* read */ | ||
375 | #define OXYGEN_AC97_RESUME 0x0002 /* write */ | ||
376 | #define OXYGEN_AC97_CLOCK_DISABLE 0x0004 | ||
377 | #define OXYGEN_AC97_NO_CODEC_0 0x0008 | ||
378 | #define OXYGEN_AC97_CODEC_0 0x0010 | ||
379 | #define OXYGEN_AC97_CODEC_1 0x0020 | ||
380 | |||
381 | #define OXYGEN_AC97_INTERRUPT_MASK 0xd2 | ||
382 | #define OXYGEN_AC97_INT_READ_DONE 0x01 | ||
383 | #define OXYGEN_AC97_INT_WRITE_DONE 0x02 | ||
384 | #define OXYGEN_AC97_INT_CODEC_0 0x10 | ||
385 | #define OXYGEN_AC97_INT_CODEC_1 0x20 | ||
386 | |||
387 | #define OXYGEN_AC97_INTERRUPT_STATUS 0xd3 | ||
388 | /* OXYGEN_AC97_INT_* */ | ||
389 | |||
390 | #define OXYGEN_AC97_OUT_CONFIG 0xd4 | ||
391 | #define OXYGEN_AC97_CODEC1_SLOT3 0x00000001 | ||
392 | #define OXYGEN_AC97_CODEC1_SLOT3_VSR 0x00000002 | ||
393 | #define OXYGEN_AC97_CODEC1_SLOT4 0x00000010 | ||
394 | #define OXYGEN_AC97_CODEC1_SLOT4_VSR 0x00000020 | ||
395 | #define OXYGEN_AC97_CODEC0_FRONTL 0x00000100 | ||
396 | #define OXYGEN_AC97_CODEC0_FRONTR 0x00000200 | ||
397 | #define OXYGEN_AC97_CODEC0_SIDEL 0x00000400 | ||
398 | #define OXYGEN_AC97_CODEC0_SIDER 0x00000800 | ||
399 | #define OXYGEN_AC97_CODEC0_CENTER 0x00001000 | ||
400 | #define OXYGEN_AC97_CODEC0_BASE 0x00002000 | ||
401 | #define OXYGEN_AC97_CODEC0_REARL 0x00004000 | ||
402 | #define OXYGEN_AC97_CODEC0_REARR 0x00008000 | ||
403 | |||
404 | #define OXYGEN_AC97_IN_CONFIG 0xd8 | ||
405 | #define OXYGEN_AC97_CODEC1_LINEL 0x00000001 | ||
406 | #define OXYGEN_AC97_CODEC1_LINEL_VSR 0x00000002 | ||
407 | #define OXYGEN_AC97_CODEC1_LINEL_16 0x00000000 | ||
408 | #define OXYGEN_AC97_CODEC1_LINEL_18 0x00000004 | ||
409 | #define OXYGEN_AC97_CODEC1_LINEL_20 0x00000008 | ||
410 | #define OXYGEN_AC97_CODEC1_LINER 0x00000010 | ||
411 | #define OXYGEN_AC97_CODEC1_LINER_VSR 0x00000020 | ||
412 | #define OXYGEN_AC97_CODEC1_LINER_16 0x00000000 | ||
413 | #define OXYGEN_AC97_CODEC1_LINER_18 0x00000040 | ||
414 | #define OXYGEN_AC97_CODEC1_LINER_20 0x00000080 | ||
415 | #define OXYGEN_AC97_CODEC0_LINEL 0x00000100 | ||
416 | #define OXYGEN_AC97_CODEC0_LINER 0x00000200 | ||
417 | |||
418 | #define OXYGEN_AC97_REGS 0xdc | ||
419 | #define OXYGEN_AC97_REG_DATA_MASK 0x0000ffff | ||
420 | #define OXYGEN_AC97_REG_ADDR_MASK 0x007f0000 | ||
421 | #define OXYGEN_AC97_REG_ADDR_SHIFT 16 | ||
422 | #define OXYGEN_AC97_REG_DIR_MASK 0x00800000 | ||
423 | #define OXYGEN_AC97_REG_DIR_WRITE 0x00000000 | ||
424 | #define OXYGEN_AC97_REG_DIR_READ 0x00800000 | ||
425 | #define OXYGEN_AC97_REG_CODEC_MASK 0x01000000 | ||
426 | #define OXYGEN_AC97_REG_CODEC_SHIFT 24 | ||
427 | |||
428 | #define OXYGEN_TEST 0xe0 | ||
429 | #define OXYGEN_TEST_RAM_SUCCEEDED 0x01 | ||
430 | #define OXYGEN_TEST_PLAYBACK_RAM 0x02 | ||
431 | #define OXYGEN_TEST_RECORD_RAM 0x04 | ||
432 | #define OXYGEN_TEST_PLL 0x08 | ||
433 | #define OXYGEN_TEST_2WIRE_LOOPBACK 0x10 | ||
434 | |||
435 | #define OXYGEN_DMA_FLUSH 0xe1 | ||
436 | /* OXYGEN_CHANNEL_* */ | ||
437 | |||
438 | #define OXYGEN_CODEC_VERSION 0xe4 | ||
439 | #define OXYGEN_XCID_MASK 0x07 | ||
440 | |||
441 | #define OXYGEN_REVISION 0xe6 | ||
442 | #define OXYGEN_REVISION_XPKGID_MASK 0x0007 | ||
443 | #define OXYGEN_REVISION_MASK 0xfff8 | ||
444 | #define OXYGEN_REVISION_2 0x0008 /* bit flag */ | ||
445 | #define OXYGEN_REVISION_8787 0x0014 /* 8 bits */ | ||
446 | |||
447 | #define OXYGEN_OFFSIN_48K 0xe8 | ||
448 | #define OXYGEN_OFFSBASE_48K 0xe9 | ||
449 | #define OXYGEN_OFFSBASE_MASK 0x0fff | ||
450 | #define OXYGEN_OFFSIN_44K 0xec | ||
451 | #define OXYGEN_OFFSBASE_44K 0xed | ||
452 | |||
453 | #endif | ||
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c new file mode 100644 index 000000000000..40e92f5cd69c --- /dev/null +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * C-Media CMI8788 driver for Asus Xonar cards | ||
3 | * | ||
4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
5 | * | ||
6 | * | ||
7 | * This driver is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2. | ||
9 | * | ||
10 | * This driver is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this driver; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | /* | ||
21 | * CMI8788: | ||
22 | * | ||
23 | * SPI 0 -> 1st PCM1796 (front) | ||
24 | * SPI 1 -> 2nd PCM1796 (surround) | ||
25 | * SPI 2 -> 3rd PCM1796 (center/LFE) | ||
26 | * SPI 4 -> 4th PCM1796 (back) | ||
27 | * | ||
28 | * GPIO 2 -> M0 of CS5381 | ||
29 | * GPIO 3 -> M1 of CS5381 | ||
30 | * GPIO 5 <- external power present (D2X only) | ||
31 | * GPIO 7 -> ALT | ||
32 | * GPIO 8 -> enable output to speakers | ||
33 | * | ||
34 | * CM9780: | ||
35 | * | ||
36 | * GPIO 0 -> enable AC'97 bypass (line in -> ADC) | ||
37 | */ | ||
38 | |||
39 | #include <linux/pci.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/mutex.h> | ||
42 | #include <sound/ac97_codec.h> | ||
43 | #include <sound/control.h> | ||
44 | #include <sound/core.h> | ||
45 | #include <sound/initval.h> | ||
46 | #include <sound/pcm.h> | ||
47 | #include <sound/tlv.h> | ||
48 | #include "oxygen.h" | ||
49 | #include "cm9780.h" | ||
50 | |||
51 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
52 | MODULE_DESCRIPTION("Asus AV200 driver"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | MODULE_SUPPORTED_DEVICE("{{Asus,AV200}}"); | ||
55 | |||
56 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
57 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
58 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
59 | |||
60 | module_param_array(index, int, NULL, 0444); | ||
61 | MODULE_PARM_DESC(index, "card index"); | ||
62 | module_param_array(id, charp, NULL, 0444); | ||
63 | MODULE_PARM_DESC(id, "ID string"); | ||
64 | module_param_array(enable, bool, NULL, 0444); | ||
65 | MODULE_PARM_DESC(enable, "enable card"); | ||
66 | |||
67 | static struct pci_device_id xonar_ids[] __devinitdata = { | ||
68 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, /* Asus Xonar D2 */ | ||
69 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, /* Asus Xonar D2X */ | ||
70 | { } | ||
71 | }; | ||
72 | MODULE_DEVICE_TABLE(pci, xonar_ids); | ||
73 | |||
74 | |||
75 | #define GPIO_CS5381_M_MASK 0x000c | ||
76 | #define GPIO_CS5381_M_SINGLE 0x0000 | ||
77 | #define GPIO_CS5381_M_DOUBLE 0x0004 | ||
78 | #define GPIO_CS5381_M_QUAD 0x0008 | ||
79 | #define GPIO_EXT_POWER 0x0020 | ||
80 | #define GPIO_ALT 0x0080 | ||
81 | #define GPIO_OUTPUT_ENABLE 0x0100 | ||
82 | |||
83 | #define GPIO_LINE_MUTE CM9780_GPO0 | ||
84 | |||
85 | /* register 16 */ | ||
86 | #define PCM1796_ATL_MASK 0xff | ||
87 | /* register 17 */ | ||
88 | #define PCM1796_ATR_MASK 0xff | ||
89 | /* register 18 */ | ||
90 | #define PCM1796_MUTE 0x01 | ||
91 | #define PCM1796_DME 0x02 | ||
92 | #define PCM1796_DMF_MASK 0x0c | ||
93 | #define PCM1796_DMF_DISABLED 0x00 | ||
94 | #define PCM1796_DMF_48 0x04 | ||
95 | #define PCM1796_DMF_441 0x08 | ||
96 | #define PCM1796_DMF_32 0x0c | ||
97 | #define PCM1796_FMT_MASK 0x70 | ||
98 | #define PCM1796_FMT_16_RJUST 0x00 | ||
99 | #define PCM1796_FMT_20_RJUST 0x10 | ||
100 | #define PCM1796_FMT_24_RJUST 0x20 | ||
101 | #define PCM1796_FMT_24_LJUST 0x30 | ||
102 | #define PCM1796_FMT_16_I2S 0x40 | ||
103 | #define PCM1796_FMT_24_I2S 0x50 | ||
104 | #define PCM1796_ATLD 0x80 | ||
105 | /* register 19 */ | ||
106 | #define PCM1796_INZD 0x01 | ||
107 | #define PCM1796_FLT_MASK 0x02 | ||
108 | #define PCM1796_FLT_SHARP 0x00 | ||
109 | #define PCM1796_FLT_SLOW 0x02 | ||
110 | #define PCM1796_DFMS 0x04 | ||
111 | #define PCM1796_OPE 0x10 | ||
112 | #define PCM1796_ATS_MASK 0x60 | ||
113 | #define PCM1796_ATS_1 0x00 | ||
114 | #define PCM1796_ATS_2 0x20 | ||
115 | #define PCM1796_ATS_4 0x40 | ||
116 | #define PCM1796_ATS_8 0x60 | ||
117 | #define PCM1796_REV 0x80 | ||
118 | /* register 20 */ | ||
119 | #define PCM1796_OS_MASK 0x03 | ||
120 | #define PCM1796_OS_64 0x00 | ||
121 | #define PCM1796_OS_32 0x01 | ||
122 | #define PCM1796_OS_128 0x02 | ||
123 | #define PCM1796_CHSL_MASK 0x04 | ||
124 | #define PCM1796_CHSL_LEFT 0x00 | ||
125 | #define PCM1796_CHSL_RIGHT 0x04 | ||
126 | #define PCM1796_MONO 0x08 | ||
127 | #define PCM1796_DFTH 0x10 | ||
128 | #define PCM1796_DSD 0x20 | ||
129 | #define PCM1796_SRST 0x40 | ||
130 | /* register 21 */ | ||
131 | #define PCM1796_PCMZ 0x01 | ||
132 | #define PCM1796_DZ_MASK 0x06 | ||
133 | /* register 22 */ | ||
134 | #define PCM1796_ZFGL 0x01 | ||
135 | #define PCM1796_ZFGR 0x02 | ||
136 | /* register 23 */ | ||
137 | #define PCM1796_ID_MASK 0x1f | ||
138 | |||
139 | struct xonar_data { | ||
140 | u8 is_d2x; | ||
141 | u8 has_power; | ||
142 | }; | ||
143 | |||
144 | static void pcm1796_write(struct oxygen *chip, unsigned int codec, | ||
145 | u8 reg, u8 value) | ||
146 | { | ||
147 | /* maps ALSA channel pair number to SPI output */ | ||
148 | static const u8 codec_map[4] = { | ||
149 | 0, 1, 2, 4 | ||
150 | }; | ||
151 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
152 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
153 | OXYGEN_SPI_CLOCK_160 | | ||
154 | (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | | ||
155 | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, | ||
156 | (reg << 8) | value); | ||
157 | } | ||
158 | |||
159 | static void xonar_init(struct oxygen *chip) | ||
160 | { | ||
161 | struct xonar_data *data = chip->model_data; | ||
162 | unsigned int i; | ||
163 | |||
164 | data->is_d2x = chip->pci->subsystem_device == 0x82b7; | ||
165 | |||
166 | for (i = 0; i < 4; ++i) { | ||
167 | pcm1796_write(chip, i, 18, PCM1796_FMT_24_LJUST | PCM1796_ATLD); | ||
168 | pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); | ||
169 | pcm1796_write(chip, i, 20, PCM1796_OS_64); | ||
170 | pcm1796_write(chip, i, 21, 0); | ||
171 | pcm1796_write(chip, i, 16, 0xff); /* set ATL/ATR after ATLD */ | ||
172 | pcm1796_write(chip, i, 17, 0xff); | ||
173 | } | ||
174 | |||
175 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
176 | GPIO_CS5381_M_MASK | GPIO_ALT); | ||
177 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
178 | GPIO_CS5381_M_SINGLE, | ||
179 | GPIO_CS5381_M_MASK | GPIO_ALT); | ||
180 | if (data->is_d2x) { | ||
181 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | ||
182 | GPIO_EXT_POWER); | ||
183 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, | ||
184 | GPIO_EXT_POWER); | ||
185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
186 | data->has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
187 | & GPIO_EXT_POWER); | ||
188 | } | ||
189 | oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); | ||
190 | oxygen_ac97_clear_bits(chip, 0, CM9780_GPIO_STATUS, GPIO_LINE_MUTE); | ||
191 | msleep(300); | ||
192 | oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_OUTPUT_ENABLE); | ||
193 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
194 | |||
195 | snd_component_add(chip->card, "PCM1796"); | ||
196 | snd_component_add(chip->card, "CS5381"); | ||
197 | } | ||
198 | |||
199 | static void xonar_cleanup(struct oxygen *chip) | ||
200 | { | ||
201 | oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); | ||
202 | } | ||
203 | |||
204 | static void set_pcm1796_params(struct oxygen *chip, | ||
205 | struct snd_pcm_hw_params *params) | ||
206 | { | ||
207 | #if 0 | ||
208 | unsigned int i; | ||
209 | u8 value; | ||
210 | |||
211 | value = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; | ||
212 | for (i = 0; i < 4; ++i) | ||
213 | pcm1796_write(chip, i, 20, value); | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | static void update_pcm1796_volume(struct oxygen *chip) | ||
218 | { | ||
219 | unsigned int i; | ||
220 | |||
221 | for (i = 0; i < 4; ++i) { | ||
222 | pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); | ||
223 | pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | static void update_pcm1796_mute(struct oxygen *chip) | ||
228 | { | ||
229 | unsigned int i; | ||
230 | u8 value; | ||
231 | |||
232 | value = PCM1796_FMT_24_LJUST | PCM1796_ATLD; | ||
233 | if (chip->dac_mute) | ||
234 | value |= PCM1796_MUTE; | ||
235 | for (i = 0; i < 4; ++i) | ||
236 | pcm1796_write(chip, i, 18, value); | ||
237 | } | ||
238 | |||
239 | static void set_cs5381_params(struct oxygen *chip, | ||
240 | struct snd_pcm_hw_params *params) | ||
241 | { | ||
242 | unsigned int value; | ||
243 | |||
244 | if (params_rate(params) <= 54000) | ||
245 | value = GPIO_CS5381_M_SINGLE; | ||
246 | else if (params_rate(params) <= 108000) | ||
247 | value = GPIO_CS5381_M_DOUBLE; | ||
248 | else | ||
249 | value = GPIO_CS5381_M_QUAD; | ||
250 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
251 | value, GPIO_CS5381_M_MASK); | ||
252 | } | ||
253 | |||
254 | static void xonar_gpio_changed(struct oxygen *chip) | ||
255 | { | ||
256 | struct xonar_data *data = chip->model_data; | ||
257 | u8 has_power; | ||
258 | |||
259 | if (!data->is_d2x) | ||
260 | return; | ||
261 | has_power = !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) | ||
262 | & GPIO_EXT_POWER); | ||
263 | if (has_power != data->has_power) { | ||
264 | data->has_power = has_power; | ||
265 | if (has_power) { | ||
266 | snd_printk(KERN_NOTICE "power restored\n"); | ||
267 | } else { | ||
268 | snd_printk(KERN_CRIT | ||
269 | "Hey! Don't unplug the power cable!\n"); | ||
270 | /* TODO: stop PCMs */ | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static void mute_ac97_ctl(struct oxygen *chip, unsigned int control) | ||
276 | { | ||
277 | unsigned int index = chip->controls[control]->private_value & 0xff; | ||
278 | u16 value; | ||
279 | |||
280 | value = oxygen_read_ac97(chip, 0, index); | ||
281 | if (!(value & 0x8000)) { | ||
282 | oxygen_write_ac97(chip, 0, index, value | 0x8000); | ||
283 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
284 | &chip->controls[control]->id); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void xonar_ac97_switch_hook(struct oxygen *chip, unsigned int codec, | ||
289 | unsigned int reg, int mute) | ||
290 | { | ||
291 | if (codec != 0) | ||
292 | return; | ||
293 | /* line-in is exclusive */ | ||
294 | switch (reg) { | ||
295 | case AC97_LINE: | ||
296 | oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS, | ||
297 | mute ? GPIO_LINE_MUTE : 0, | ||
298 | GPIO_LINE_MUTE); | ||
299 | if (!mute) { | ||
300 | mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH); | ||
301 | mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH); | ||
302 | mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH); | ||
303 | } | ||
304 | break; | ||
305 | case AC97_MIC: | ||
306 | case AC97_CD: | ||
307 | case AC97_VIDEO: | ||
308 | case AC97_AUX: | ||
309 | if (!mute) { | ||
310 | oxygen_ac97_set_bits(chip, 0, CM9780_GPIO_STATUS, | ||
311 | GPIO_LINE_MUTE); | ||
312 | mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH); | ||
313 | } | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | static int pcm1796_volume_info(struct snd_kcontrol *ctl, | ||
319 | struct snd_ctl_elem_info *info) | ||
320 | { | ||
321 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
322 | info->count = 8; | ||
323 | info->value.integer.min = 0x0f; | ||
324 | info->value.integer.max = 0xff; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int alt_switch_get(struct snd_kcontrol *ctl, | ||
329 | struct snd_ctl_elem_value *value) | ||
330 | { | ||
331 | struct oxygen *chip = ctl->private_data; | ||
332 | |||
333 | value->value.integer.value[0] = | ||
334 | !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_ALT); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int alt_switch_put(struct snd_kcontrol *ctl, | ||
339 | struct snd_ctl_elem_value *value) | ||
340 | { | ||
341 | struct oxygen *chip = ctl->private_data; | ||
342 | u16 old_bits, new_bits; | ||
343 | int changed; | ||
344 | |||
345 | spin_lock_irq(&chip->reg_lock); | ||
346 | old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
347 | if (value->value.integer.value[0]) | ||
348 | new_bits = old_bits | GPIO_ALT; | ||
349 | else | ||
350 | new_bits = old_bits & ~GPIO_ALT; | ||
351 | changed = new_bits != old_bits; | ||
352 | if (changed) | ||
353 | oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); | ||
354 | spin_unlock_irq(&chip->reg_lock); | ||
355 | return changed; | ||
356 | } | ||
357 | |||
358 | static const struct snd_kcontrol_new alt_switch = { | ||
359 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
360 | .name = "Analog Loopback Switch", | ||
361 | .info = snd_ctl_boolean_mono_info, | ||
362 | .get = alt_switch_get, | ||
363 | .put = alt_switch_put, | ||
364 | }; | ||
365 | |||
366 | static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -12000, 50, 0); | ||
367 | |||
368 | static int xonar_control_filter(struct snd_kcontrol_new *template) | ||
369 | { | ||
370 | if (!strcmp(template->name, "Master Playback Volume")) { | ||
371 | template->access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
372 | template->info = pcm1796_volume_info, | ||
373 | template->tlv.p = pcm1796_db_scale; | ||
374 | } else if (!strncmp(template->name, "CD Capture ", 11)) { | ||
375 | /* CD in is actually connected to the video in pin */ | ||
376 | template->private_value ^= AC97_CD ^ AC97_VIDEO; | ||
377 | } else if (!strcmp(template->name, "Line Capture Volume")) { | ||
378 | return 1; /* line-in bypasses the AC'97 mixer */ | ||
379 | } | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int xonar_mixer_init(struct oxygen *chip) | ||
384 | { | ||
385 | return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); | ||
386 | } | ||
387 | |||
388 | static const struct oxygen_model model_xonar = { | ||
389 | .shortname = "Asus AV200", | ||
390 | .longname = "Asus Virtuoso 200", | ||
391 | .chip = "AV200", | ||
392 | .init = xonar_init, | ||
393 | .control_filter = xonar_control_filter, | ||
394 | .mixer_init = xonar_mixer_init, | ||
395 | .cleanup = xonar_cleanup, | ||
396 | .set_dac_params = set_pcm1796_params, | ||
397 | .set_adc_params = set_cs5381_params, | ||
398 | .update_dac_volume = update_pcm1796_volume, | ||
399 | .update_dac_mute = update_pcm1796_mute, | ||
400 | .ac97_switch_hook = xonar_ac97_switch_hook, | ||
401 | .gpio_changed = xonar_gpio_changed, | ||
402 | .model_data_size = sizeof(struct xonar_data), | ||
403 | .dac_channels = 8, | ||
404 | .used_channels = OXYGEN_CHANNEL_B | | ||
405 | OXYGEN_CHANNEL_C | | ||
406 | OXYGEN_CHANNEL_SPDIF | | ||
407 | OXYGEN_CHANNEL_MULTICH, | ||
408 | .function_flags = OXYGEN_FUNCTION_ENABLE_SPI_4_5, | ||
409 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
410 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
411 | }; | ||
412 | |||
413 | static int __devinit xonar_probe(struct pci_dev *pci, | ||
414 | const struct pci_device_id *pci_id) | ||
415 | { | ||
416 | static int dev; | ||
417 | int err; | ||
418 | |||
419 | if (dev >= SNDRV_CARDS) | ||
420 | return -ENODEV; | ||
421 | if (!enable[dev]) { | ||
422 | ++dev; | ||
423 | return -ENOENT; | ||
424 | } | ||
425 | err = oxygen_pci_probe(pci, index[dev], id[dev], 1, &model_xonar); | ||
426 | if (err >= 0) | ||
427 | ++dev; | ||
428 | return err; | ||
429 | } | ||
430 | |||
431 | static struct pci_driver xonar_driver = { | ||
432 | .name = "AV200", | ||
433 | .id_table = xonar_ids, | ||
434 | .probe = xonar_probe, | ||
435 | .remove = __devexit_p(oxygen_pci_remove), | ||
436 | }; | ||
437 | |||
438 | static int __init alsa_card_xonar_init(void) | ||
439 | { | ||
440 | return pci_register_driver(&xonar_driver); | ||
441 | } | ||
442 | |||
443 | static void __exit alsa_card_xonar_exit(void) | ||
444 | { | ||
445 | pci_unregister_driver(&xonar_driver); | ||
446 | } | ||
447 | |||
448 | module_init(alsa_card_xonar_init) | ||
449 | module_exit(alsa_card_xonar_exit) | ||
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 2d618bd7e62b..9d5bb76229a8 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
@@ -21,7 +21,6 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index 0ff8dc36fde3..c4e415d07380 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index d55d8bc90eee..e6a4bfbb91bb 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
25 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index 5f8d42633b04..aabc7bc5321e 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -120,8 +119,18 @@ static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | |||
120 | is_capture = (kcontrol->private_value != 0); | 119 | is_capture = (kcontrol->private_value != 0); |
121 | for (i = 0; i < 2; i++) { | 120 | for (i = 0; i < 2; i++) { |
122 | int new_volume = ucontrol->value.integer.value[i]; | 121 | int new_volume = ucontrol->value.integer.value[i]; |
123 | int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : | 122 | int *stored_volume = is_capture ? |
123 | &chip->analog_capture_volume[i] : | ||
124 | &chip->analog_playback_volume[i]; | 124 | &chip->analog_playback_volume[i]; |
125 | if (is_capture) { | ||
126 | if (new_volume < PCXHR_ANALOG_CAPTURE_LEVEL_MIN || | ||
127 | new_volume > PCXHR_ANALOG_CAPTURE_LEVEL_MAX) | ||
128 | continue; | ||
129 | } else { | ||
130 | if (new_volume < PCXHR_ANALOG_PLAYBACK_LEVEL_MIN || | ||
131 | new_volume > PCXHR_ANALOG_PLAYBACK_LEVEL_MAX) | ||
132 | continue; | ||
133 | } | ||
125 | if (*stored_volume != new_volume) { | 134 | if (*stored_volume != new_volume) { |
126 | *stored_volume = new_volume; | 135 | *stored_volume = new_volume; |
127 | changed = 1; | 136 | changed = 1; |
@@ -165,10 +174,13 @@ static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | |||
165 | int i, changed = 0; | 174 | int i, changed = 0; |
166 | mutex_lock(&chip->mgr->mixer_mutex); | 175 | mutex_lock(&chip->mgr->mixer_mutex); |
167 | for(i = 0; i < 2; i++) { | 176 | for(i = 0; i < 2; i++) { |
168 | if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { | 177 | if (chip->analog_playback_active[i] != |
169 | chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; | 178 | ucontrol->value.integer.value[i]) { |
179 | chip->analog_playback_active[i] = | ||
180 | !!ucontrol->value.integer.value[i]; | ||
170 | changed = 1; | 181 | changed = 1; |
171 | pcxhr_update_analog_audio_level(chip, 0, i); /* update playback levels */ | 182 | /* update playback levels */ |
183 | pcxhr_update_analog_audio_level(chip, 0, i); | ||
172 | } | 184 | } |
173 | } | 185 | } |
174 | mutex_unlock(&chip->mgr->mixer_mutex); | 186 | mutex_unlock(&chip->mgr->mixer_mutex); |
@@ -323,20 +335,24 @@ static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
323 | int i; | 335 | int i; |
324 | 336 | ||
325 | mutex_lock(&chip->mgr->mixer_mutex); | 337 | mutex_lock(&chip->mgr->mixer_mutex); |
326 | if (is_capture) | 338 | if (is_capture) /* digital capture */ |
327 | stored_volume = chip->digital_capture_volume; /* digital capture */ | 339 | stored_volume = chip->digital_capture_volume; |
328 | else | 340 | else /* digital playback */ |
329 | stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ | 341 | stored_volume = chip->digital_playback_volume[idx]; |
330 | for (i = 0; i < 2; i++) { | 342 | for (i = 0; i < 2; i++) { |
331 | if (stored_volume[i] != ucontrol->value.integer.value[i]) { | 343 | int vol = ucontrol->value.integer.value[i]; |
332 | stored_volume[i] = ucontrol->value.integer.value[i]; | 344 | if (vol < PCXHR_DIGITAL_LEVEL_MIN || |
345 | vol > PCXHR_DIGITAL_LEVEL_MAX) | ||
346 | continue; | ||
347 | if (stored_volume[i] != vol) { | ||
348 | stored_volume[i] = vol; | ||
333 | changed = 1; | 349 | changed = 1; |
334 | if (is_capture) /* update capture volume */ | 350 | if (is_capture) /* update capture volume */ |
335 | pcxhr_update_audio_pipe_level(chip, 1, i); | 351 | pcxhr_update_audio_pipe_level(chip, 1, i); |
336 | } | 352 | } |
337 | } | 353 | } |
338 | if (! is_capture && changed) | 354 | if (!is_capture && changed) /* update playback volume */ |
339 | pcxhr_update_playback_stream_level(chip, idx); /* update playback volume */ | 355 | pcxhr_update_playback_stream_level(chip, idx); |
340 | mutex_unlock(&chip->mgr->mixer_mutex); | 356 | mutex_unlock(&chip->mgr->mixer_mutex); |
341 | return changed; | 357 | return changed; |
342 | } | 358 | } |
@@ -378,8 +394,10 @@ static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
378 | mutex_lock(&chip->mgr->mixer_mutex); | 394 | mutex_lock(&chip->mgr->mixer_mutex); |
379 | j = idx; | 395 | j = idx; |
380 | for (i = 0; i < 2; i++) { | 396 | for (i = 0; i < 2; i++) { |
381 | if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { | 397 | if (chip->digital_playback_active[j][i] != |
382 | chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; | 398 | ucontrol->value.integer.value[i]) { |
399 | chip->digital_playback_active[j][i] = | ||
400 | !!ucontrol->value.integer.value[i]; | ||
383 | changed = 1; | 401 | changed = 1; |
384 | } | 402 | } |
385 | } | 403 | } |
@@ -423,10 +441,13 @@ static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | |||
423 | 441 | ||
424 | mutex_lock(&chip->mgr->mixer_mutex); | 442 | mutex_lock(&chip->mgr->mixer_mutex); |
425 | for (i = 0; i < 2; i++) { | 443 | for (i = 0; i < 2; i++) { |
426 | if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { | 444 | if (chip->monitoring_volume[i] != |
427 | chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; | 445 | ucontrol->value.integer.value[i]) { |
428 | if(chip->monitoring_active[i]) /* do only when monitoring is unmuted */ | 446 | chip->monitoring_volume[i] = |
447 | !!ucontrol->value.integer.value[i]; | ||
448 | if(chip->monitoring_active[i]) | ||
429 | /* update monitoring volume and mute */ | 449 | /* update monitoring volume and mute */ |
450 | /* do only when monitoring is unmuted */ | ||
430 | pcxhr_update_audio_pipe_level(chip, 0, i); | 451 | pcxhr_update_audio_pipe_level(chip, 0, i); |
431 | changed = 1; | 452 | changed = 1; |
432 | } | 453 | } |
@@ -470,15 +491,17 @@ static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | |||
470 | 491 | ||
471 | mutex_lock(&chip->mgr->mixer_mutex); | 492 | mutex_lock(&chip->mgr->mixer_mutex); |
472 | for (i = 0; i < 2; i++) { | 493 | for (i = 0; i < 2; i++) { |
473 | if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { | 494 | if (chip->monitoring_active[i] != |
474 | chip->monitoring_active[i] = ucontrol->value.integer.value[i]; | 495 | ucontrol->value.integer.value[i]) { |
496 | chip->monitoring_active[i] = | ||
497 | !!ucontrol->value.integer.value[i]; | ||
475 | changed |= (1<<i); /* mask 0x01 and 0x02 */ | 498 | changed |= (1<<i); /* mask 0x01 and 0x02 */ |
476 | } | 499 | } |
477 | } | 500 | } |
478 | if(changed & 0x01) | 501 | if (changed & 0x01) |
479 | /* update left monitoring volume and mute */ | 502 | /* update left monitoring volume and mute */ |
480 | pcxhr_update_audio_pipe_level(chip, 0, 0); | 503 | pcxhr_update_audio_pipe_level(chip, 0, 0); |
481 | if(changed & 0x02) | 504 | if (changed & 0x02) |
482 | /* update right monitoring volume and mute */ | 505 | /* update right monitoring volume and mute */ |
483 | pcxhr_update_audio_pipe_level(chip, 0, 1); | 506 | pcxhr_update_audio_pipe_level(chip, 0, 1); |
484 | 507 | ||
@@ -579,6 +602,8 @@ static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | |||
579 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | 602 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
580 | int ret = 0; | 603 | int ret = 0; |
581 | 604 | ||
605 | if (ucontrol->value.enumerated.item[0] >= 3) | ||
606 | return -EINVAL; | ||
582 | mutex_lock(&chip->mgr->mixer_mutex); | 607 | mutex_lock(&chip->mgr->mixer_mutex); |
583 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { | 608 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { |
584 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; | 609 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; |
@@ -642,8 +667,11 @@ static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | |||
642 | struct snd_ctl_elem_value *ucontrol) | 667 | struct snd_ctl_elem_value *ucontrol) |
643 | { | 668 | { |
644 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | 669 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
670 | unsigned int clock_items = 3 + mgr->capture_chips; | ||
645 | int rate, ret = 0; | 671 | int rate, ret = 0; |
646 | 672 | ||
673 | if (ucontrol->value.enumerated.item[0] >= clock_items) | ||
674 | return -EINVAL; | ||
647 | mutex_lock(&mgr->mixer_mutex); | 675 | mutex_lock(&mgr->mixer_mutex); |
648 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { | 676 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { |
649 | mutex_lock(&mgr->setup_mutex); | 677 | mutex_lock(&mgr->setup_mutex); |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 8e5410483e67..9408b1eeec40 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -88,7 +88,6 @@ | |||
88 | Adopted for Windows NT driver 01/20/98 CNL | 88 | Adopted for Windows NT driver 01/20/98 CNL |
89 | */ | 89 | */ |
90 | 90 | ||
91 | #include <sound/driver.h> | ||
92 | #include <linux/delay.h> | 91 | #include <linux/delay.h> |
93 | #include <linux/init.h> | 92 | #include <linux/init.h> |
94 | #include <linux/interrupt.h> | 93 | #include <linux/interrupt.h> |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 1475912588e9..df184aabce84 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
@@ -69,7 +69,6 @@ | |||
69 | */ | 69 | */ |
70 | 70 | ||
71 | 71 | ||
72 | #include <sound/driver.h> | ||
73 | #include <linux/delay.h> | 72 | #include <linux/delay.h> |
74 | #include <linux/init.h> | 73 | #include <linux/init.h> |
75 | #include <linux/interrupt.h> | 74 | #include <linux/interrupt.h> |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 0b3c532c4014..fb0a4ee8bc02 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
@@ -2195,22 +2194,25 @@ snd_rme96_dac_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_valu | |||
2195 | { | 2194 | { |
2196 | struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); | 2195 | struct rme96 *rme96 = snd_kcontrol_chip(kcontrol); |
2197 | int change = 0; | 2196 | int change = 0; |
2197 | unsigned int vol, maxvol; | ||
2198 | 2198 | ||
2199 | if (!RME96_HAS_ANALOG_OUT(rme96)) { | 2199 | |
2200 | if (!RME96_HAS_ANALOG_OUT(rme96)) | ||
2200 | return -EINVAL; | 2201 | return -EINVAL; |
2201 | } | 2202 | maxvol = RME96_185X_MAX_OUT(rme96); |
2202 | spin_lock_irq(&rme96->lock); | 2203 | spin_lock_irq(&rme96->lock); |
2203 | if (u->value.integer.value[0] != rme96->vol[0]) { | 2204 | vol = u->value.integer.value[0]; |
2204 | rme96->vol[0] = u->value.integer.value[0]; | 2205 | if (vol != rme96->vol[0] && vol <= maxvol) { |
2205 | change = 1; | 2206 | rme96->vol[0] = vol; |
2206 | } | 2207 | change = 1; |
2207 | if (u->value.integer.value[1] != rme96->vol[1]) { | 2208 | } |
2208 | rme96->vol[1] = u->value.integer.value[1]; | 2209 | vol = u->value.integer.value[1]; |
2209 | change = 1; | 2210 | if (vol != rme96->vol[1] && vol <= maxvol) { |
2210 | } | 2211 | rme96->vol[1] = vol; |
2211 | if (change) { | 2212 | change = 1; |
2212 | snd_rme96_apply_dac_volume(rme96); | ||
2213 | } | 2213 | } |
2214 | if (change) | ||
2215 | snd_rme96_apply_dac_volume(rme96); | ||
2214 | spin_unlock_irq(&rme96->lock); | 2216 | spin_unlock_irq(&rme96->lock); |
2215 | 2217 | ||
2216 | return change; | 2218 | return change; |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index ff26a3672d40..c2bd4384316a 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
@@ -104,8 +103,6 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); | |||
104 | #define HDSP_statusRegister 0 | 103 | #define HDSP_statusRegister 0 |
105 | #define HDSP_timecode 128 | 104 | #define HDSP_timecode 128 |
106 | #define HDSP_status2Register 192 | 105 | #define HDSP_status2Register 192 |
107 | #define HDSP_midiDataOut0 352 | ||
108 | #define HDSP_midiDataOut1 356 | ||
109 | #define HDSP_midiDataIn0 360 | 106 | #define HDSP_midiDataIn0 360 |
110 | #define HDSP_midiDataIn1 364 | 107 | #define HDSP_midiDataIn1 364 |
111 | #define HDSP_midiStatusOut0 384 | 108 | #define HDSP_midiStatusOut0 384 |
@@ -610,7 +607,10 @@ static int hdsp_playback_to_output_key (struct hdsp *hdsp, int in, int out) | |||
610 | case Multiface: | 607 | case Multiface: |
611 | case Digiface: | 608 | case Digiface: |
612 | default: | 609 | default: |
613 | return (64 * out) + (32 + (in)); | 610 | if (hdsp->firmware_rev == 0xa) |
611 | return (64 * out) + (32 + (in)); | ||
612 | else | ||
613 | return (52 * out) + (26 + (in)); | ||
614 | case H9632: | 614 | case H9632: |
615 | return (32 * out) + (16 + (in)); | 615 | return (32 * out) + (16 + (in)); |
616 | case H9652: | 616 | case H9652: |
@@ -624,7 +624,10 @@ static int hdsp_input_to_output_key (struct hdsp *hdsp, int in, int out) | |||
624 | case Multiface: | 624 | case Multiface: |
625 | case Digiface: | 625 | case Digiface: |
626 | default: | 626 | default: |
627 | return (64 * out) + in; | 627 | if (hdsp->firmware_rev == 0xa) |
628 | return (64 * out) + in; | ||
629 | else | ||
630 | return (52 * out) + in; | ||
628 | case H9632: | 631 | case H9632: |
629 | return (32 * out) + in; | 632 | return (32 * out) + in; |
630 | case H9652: | 633 | case H9652: |
@@ -2121,7 +2124,7 @@ static int snd_hdsp_put_clock_source_lock(struct snd_kcontrol *kcontrol, struct | |||
2121 | 2124 | ||
2122 | change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked; | 2125 | change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked; |
2123 | if (change) | 2126 | if (change) |
2124 | hdsp->clock_source_locked = ucontrol->value.integer.value[0]; | 2127 | hdsp->clock_source_locked = !!ucontrol->value.integer.value[0]; |
2125 | return change; | 2128 | return change; |
2126 | } | 2129 | } |
2127 | 2130 | ||
@@ -3558,7 +3561,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
3558 | 3561 | ||
3559 | } | 3562 | } |
3560 | 3563 | ||
3561 | static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp) | 3564 | static void snd_hdsp_proc_init(struct hdsp *hdsp) |
3562 | { | 3565 | { |
3563 | struct snd_info_entry *entry; | 3566 | struct snd_info_entry *entry; |
3564 | 3567 | ||
@@ -3606,7 +3609,7 @@ static int snd_hdsp_set_defaults(struct hdsp *hdsp) | |||
3606 | 3609 | ||
3607 | /* ASSUMPTION: hdsp->lock is either held, or | 3610 | /* ASSUMPTION: hdsp->lock is either held, or |
3608 | there is no need to hold it (e.g. during module | 3611 | there is no need to hold it (e.g. during module |
3609 | initalization). | 3612 | initialization). |
3610 | */ | 3613 | */ |
3611 | 3614 | ||
3612 | /* set defaults: | 3615 | /* set defaults: |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index f1bdda6cbcff..9a19ae6a64d9 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
29 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
@@ -3348,7 +3347,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
3348 | unsigned int i; | 3347 | unsigned int i; |
3349 | 3348 | ||
3350 | /* ASSUMPTION: hdspm->lock is either held, or there is no need to | 3349 | /* ASSUMPTION: hdspm->lock is either held, or there is no need to |
3351 | hold it (e.g. during module initalization). | 3350 | hold it (e.g. during module initialization). |
3352 | */ | 3351 | */ |
3353 | 3352 | ||
3354 | /* set defaults: */ | 3353 | /* set defaults: */ |
@@ -3416,7 +3415,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) | |||
3416 | 3415 | ||
3417 | 3416 | ||
3418 | /*------------------------------------------------------------ | 3417 | /*------------------------------------------------------------ |
3419 | interupt | 3418 | interrupt |
3420 | ------------------------------------------------------------*/ | 3419 | ------------------------------------------------------------*/ |
3421 | 3420 | ||
3422 | static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) | 3421 | static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) |
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 34f96f12e5bf..a123f0e6ba23 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -148,7 +147,7 @@ MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall}," | |||
148 | #define RME9652_start_bit (1<<0) /* start record/play */ | 147 | #define RME9652_start_bit (1<<0) /* start record/play */ |
149 | /* bits 1-3 encode buffersize/latency */ | 148 | /* bits 1-3 encode buffersize/latency */ |
150 | #define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */ | 149 | #define RME9652_Master (1<<4) /* Clock Mode Master=1,Slave/Auto=0 */ |
151 | #define RME9652_IE (1<<5) /* Interupt Enable */ | 150 | #define RME9652_IE (1<<5) /* Interrupt Enable */ |
152 | #define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */ | 151 | #define RME9652_freq (1<<6) /* samplerate 0=44.1/88.2, 1=48/96 kHz */ |
153 | #define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */ | 152 | #define RME9652_freq1 (1<<7) /* if 0, 32kHz, else always 1 */ |
154 | #define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ | 153 | #define RME9652_DS (1<<8) /* Doule Speed 0=44.1/48, 1=88.2/96 Khz */ |
@@ -1826,7 +1825,7 @@ static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652) | |||
1826 | 1825 | ||
1827 | /* ASSUMPTION: rme9652->lock is either held, or | 1826 | /* ASSUMPTION: rme9652->lock is either held, or |
1828 | there is no need to hold it (e.g. during module | 1827 | there is no need to hold it (e.g. during module |
1829 | initalization). | 1828 | initialization). |
1830 | */ | 1829 | */ |
1831 | 1830 | ||
1832 | /* set defaults: | 1831 | /* set defaults: |
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c new file mode 100644 index 000000000000..dcd7cd010461 --- /dev/null +++ b/sound/pci/sis7019.c | |||
@@ -0,0 +1,1460 @@ | |||
1 | /* | ||
2 | * Driver for SiS7019 Audio Accelerator | ||
3 | * | ||
4 | * Copyright (C) 2004-2007, David Dillow | ||
5 | * Written by David Dillow <dave@thedillows.org> | ||
6 | * Inspired by the Trident 4D-WaveDX/NX driver. | ||
7 | * | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation, version 2. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/time.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/ac97_codec.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include "sis7019.h" | ||
34 | |||
35 | MODULE_AUTHOR("David Dillow <dave@thedillows.org>"); | ||
36 | MODULE_DESCRIPTION("SiS7019"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}"); | ||
39 | |||
40 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | ||
41 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | ||
42 | static int enable = 1; | ||
43 | |||
44 | module_param(index, int, 0444); | ||
45 | MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator."); | ||
46 | module_param(id, charp, 0444); | ||
47 | MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); | ||
48 | module_param(enable, bool, 0444); | ||
49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); | ||
50 | |||
51 | static struct pci_device_id snd_sis7019_ids[] = { | ||
52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, | ||
53 | { 0, } | ||
54 | }; | ||
55 | |||
56 | MODULE_DEVICE_TABLE(pci, snd_sis7019_ids); | ||
57 | |||
58 | /* There are three timing modes for the voices. | ||
59 | * | ||
60 | * For both playback and capture, when the buffer is one or two periods long, | ||
61 | * we use the hardware's built-in Mid-Loop Interrupt and End-Loop Interrupt | ||
62 | * to let us know when the periods have ended. | ||
63 | * | ||
64 | * When performing playback with more than two periods per buffer, we set | ||
65 | * the "Stop Sample Offset" and tell the hardware to interrupt us when we | ||
66 | * reach it. We then update the offset and continue on until we are | ||
67 | * interrupted for the next period. | ||
68 | * | ||
69 | * Capture channels do not have a SSO, so we allocate a playback channel to | ||
70 | * use as a timer for the capture periods. We use the SSO on the playback | ||
71 | * channel to clock out virtual periods, and adjust the virtual period length | ||
72 | * to maintain synchronization. This algorithm came from the Trident driver. | ||
73 | * | ||
74 | * FIXME: It'd be nice to make use of some of the synth features in the | ||
75 | * hardware, but a woeful lack of documentation is a significant roadblock. | ||
76 | */ | ||
77 | struct voice { | ||
78 | u16 flags; | ||
79 | #define VOICE_IN_USE 1 | ||
80 | #define VOICE_CAPTURE 2 | ||
81 | #define VOICE_SSO_TIMING 4 | ||
82 | #define VOICE_SYNC_TIMING 8 | ||
83 | u16 sync_cso; | ||
84 | u16 period_size; | ||
85 | u16 buffer_size; | ||
86 | u16 sync_period_size; | ||
87 | u16 sync_buffer_size; | ||
88 | u32 sso; | ||
89 | u32 vperiod; | ||
90 | struct snd_pcm_substream *substream; | ||
91 | struct voice *timing; | ||
92 | void __iomem *ctrl_base; | ||
93 | void __iomem *wave_base; | ||
94 | void __iomem *sync_base; | ||
95 | int num; | ||
96 | }; | ||
97 | |||
98 | /* We need four pages to store our wave parameters during a suspend. If | ||
99 | * we're not doing power management, we still need to allocate a page | ||
100 | * for the silence buffer. | ||
101 | */ | ||
102 | #ifdef CONFIG_PM | ||
103 | #define SIS_SUSPEND_PAGES 4 | ||
104 | #else | ||
105 | #define SIS_SUSPEND_PAGES 1 | ||
106 | #endif | ||
107 | |||
108 | struct sis7019 { | ||
109 | unsigned long ioport; | ||
110 | void __iomem *ioaddr; | ||
111 | int irq; | ||
112 | int codecs_present; | ||
113 | |||
114 | struct pci_dev *pci; | ||
115 | struct snd_pcm *pcm; | ||
116 | struct snd_card *card; | ||
117 | struct snd_ac97 *ac97[3]; | ||
118 | |||
119 | /* Protect against more than one thread hitting the AC97 | ||
120 | * registers (in a more polite manner than pounding the hardware | ||
121 | * semaphore) | ||
122 | */ | ||
123 | struct mutex ac97_mutex; | ||
124 | |||
125 | /* voice_lock protects allocation/freeing of the voice descriptions | ||
126 | */ | ||
127 | spinlock_t voice_lock; | ||
128 | |||
129 | struct voice voices[64]; | ||
130 | struct voice capture_voice; | ||
131 | |||
132 | /* Allocate pages to store the internal wave state during | ||
133 | * suspends. When we're operating, this can be used as a silence | ||
134 | * buffer for a timing channel. | ||
135 | */ | ||
136 | void *suspend_state[SIS_SUSPEND_PAGES]; | ||
137 | |||
138 | int silence_users; | ||
139 | dma_addr_t silence_dma_addr; | ||
140 | }; | ||
141 | |||
142 | #define SIS_PRIMARY_CODEC_PRESENT 0x0001 | ||
143 | #define SIS_SECONDARY_CODEC_PRESENT 0x0002 | ||
144 | #define SIS_TERTIARY_CODEC_PRESENT 0x0004 | ||
145 | |||
146 | /* The HW offset parameters (Loop End, Stop Sample, End Sample) have a | ||
147 | * documented range of 8-0xfff8 samples. Given that they are 0-based, | ||
148 | * that places our period/buffer range at 9-0xfff9 samples. That makes the | ||
149 | * max buffer size 0xfff9 samples * 2 channels * 2 bytes per sample, and | ||
150 | * max samples / min samples gives us the max periods in a buffer. | ||
151 | * | ||
152 | * We'll add a constraint upon open that limits the period and buffer sample | ||
153 | * size to values that are legal for the hardware. | ||
154 | */ | ||
155 | static struct snd_pcm_hardware sis_playback_hw_info = { | ||
156 | .info = (SNDRV_PCM_INFO_MMAP | | ||
157 | SNDRV_PCM_INFO_MMAP_VALID | | ||
158 | SNDRV_PCM_INFO_INTERLEAVED | | ||
159 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
160 | SNDRV_PCM_INFO_SYNC_START | | ||
161 | SNDRV_PCM_INFO_RESUME), | ||
162 | .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | ||
163 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), | ||
164 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, | ||
165 | .rate_min = 4000, | ||
166 | .rate_max = 48000, | ||
167 | .channels_min = 1, | ||
168 | .channels_max = 2, | ||
169 | .buffer_bytes_max = (0xfff9 * 4), | ||
170 | .period_bytes_min = 9, | ||
171 | .period_bytes_max = (0xfff9 * 4), | ||
172 | .periods_min = 1, | ||
173 | .periods_max = (0xfff9 / 9), | ||
174 | }; | ||
175 | |||
176 | static struct snd_pcm_hardware sis_capture_hw_info = { | ||
177 | .info = (SNDRV_PCM_INFO_MMAP | | ||
178 | SNDRV_PCM_INFO_MMAP_VALID | | ||
179 | SNDRV_PCM_INFO_INTERLEAVED | | ||
180 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
181 | SNDRV_PCM_INFO_SYNC_START | | ||
182 | SNDRV_PCM_INFO_RESUME), | ||
183 | .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | ||
184 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE), | ||
185 | .rates = SNDRV_PCM_RATE_48000, | ||
186 | .rate_min = 4000, | ||
187 | .rate_max = 48000, | ||
188 | .channels_min = 1, | ||
189 | .channels_max = 2, | ||
190 | .buffer_bytes_max = (0xfff9 * 4), | ||
191 | .period_bytes_min = 9, | ||
192 | .period_bytes_max = (0xfff9 * 4), | ||
193 | .periods_min = 1, | ||
194 | .periods_max = (0xfff9 / 9), | ||
195 | }; | ||
196 | |||
197 | static void sis_update_sso(struct voice *voice, u16 period) | ||
198 | { | ||
199 | void __iomem *base = voice->ctrl_base; | ||
200 | |||
201 | voice->sso += period; | ||
202 | if (voice->sso >= voice->buffer_size) | ||
203 | voice->sso -= voice->buffer_size; | ||
204 | |||
205 | /* Enforce the documented hardware minimum offset */ | ||
206 | if (voice->sso < 8) | ||
207 | voice->sso = 8; | ||
208 | |||
209 | /* The SSO is in the upper 16 bits of the register. */ | ||
210 | writew(voice->sso & 0xffff, base + SIS_PLAY_DMA_SSO_ESO + 2); | ||
211 | } | ||
212 | |||
213 | static void sis_update_voice(struct voice *voice) | ||
214 | { | ||
215 | if (voice->flags & VOICE_SSO_TIMING) { | ||
216 | sis_update_sso(voice, voice->period_size); | ||
217 | } else if (voice->flags & VOICE_SYNC_TIMING) { | ||
218 | int sync; | ||
219 | |||
220 | /* If we've not hit the end of the virtual period, update | ||
221 | * our records and keep going. | ||
222 | */ | ||
223 | if (voice->vperiod > voice->period_size) { | ||
224 | voice->vperiod -= voice->period_size; | ||
225 | if (voice->vperiod < voice->period_size) | ||
226 | sis_update_sso(voice, voice->vperiod); | ||
227 | else | ||
228 | sis_update_sso(voice, voice->period_size); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | /* Calculate our relative offset between the target and | ||
233 | * the actual CSO value. Since we're operating in a loop, | ||
234 | * if the value is more than half way around, we can | ||
235 | * consider ourselves wrapped. | ||
236 | */ | ||
237 | sync = voice->sync_cso; | ||
238 | sync -= readw(voice->sync_base + SIS_CAPTURE_DMA_FORMAT_CSO); | ||
239 | if (sync > (voice->sync_buffer_size / 2)) | ||
240 | sync -= voice->sync_buffer_size; | ||
241 | |||
242 | /* If sync is positive, then we interrupted too early, and | ||
243 | * we'll need to come back in a few samples and try again. | ||
244 | * There's a minimum wait, as it takes some time for the DMA | ||
245 | * engine to startup, etc... | ||
246 | */ | ||
247 | if (sync > 0) { | ||
248 | if (sync < 16) | ||
249 | sync = 16; | ||
250 | sis_update_sso(voice, sync); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | /* Ok, we interrupted right on time, or (hopefully) just | ||
255 | * a bit late. We'll adjst our next waiting period based | ||
256 | * on how close we got. | ||
257 | * | ||
258 | * We need to stay just behind the actual channel to ensure | ||
259 | * it really is past a period when we get our interrupt -- | ||
260 | * otherwise we'll fall into the early code above and have | ||
261 | * a minimum wait time, which makes us quite late here, | ||
262 | * eating into the user's time to refresh the buffer, esp. | ||
263 | * if using small periods. | ||
264 | * | ||
265 | * If we're less than 9 samples behind, we're on target. | ||
266 | */ | ||
267 | if (sync > -9) | ||
268 | voice->vperiod = voice->sync_period_size + 1; | ||
269 | else | ||
270 | voice->vperiod = voice->sync_period_size - 4; | ||
271 | |||
272 | if (voice->vperiod < voice->buffer_size) { | ||
273 | sis_update_sso(voice, voice->vperiod); | ||
274 | voice->vperiod = 0; | ||
275 | } else | ||
276 | sis_update_sso(voice, voice->period_size); | ||
277 | |||
278 | sync = voice->sync_cso + voice->sync_period_size; | ||
279 | if (sync >= voice->sync_buffer_size) | ||
280 | sync -= voice->sync_buffer_size; | ||
281 | voice->sync_cso = sync; | ||
282 | } | ||
283 | |||
284 | snd_pcm_period_elapsed(voice->substream); | ||
285 | } | ||
286 | |||
287 | static void sis_voice_irq(u32 status, struct voice *voice) | ||
288 | { | ||
289 | int bit; | ||
290 | |||
291 | while (status) { | ||
292 | bit = __ffs(status); | ||
293 | status >>= bit + 1; | ||
294 | voice += bit; | ||
295 | sis_update_voice(voice); | ||
296 | voice++; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static irqreturn_t sis_interrupt(int irq, void *dev) | ||
301 | { | ||
302 | struct sis7019 *sis = dev; | ||
303 | unsigned long io = sis->ioport; | ||
304 | struct voice *voice; | ||
305 | u32 intr, status; | ||
306 | |||
307 | /* We only use the DMA interrupts, and we don't enable any other | ||
308 | * source of interrupts. But, it is possible to see an interupt | ||
309 | * status that didn't actually interrupt us, so eliminate anything | ||
310 | * we're not expecting to avoid falsely claiming an IRQ, and an | ||
311 | * ensuing endless loop. | ||
312 | */ | ||
313 | intr = inl(io + SIS_GISR); | ||
314 | intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | | ||
315 | SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; | ||
316 | if (!intr) | ||
317 | return IRQ_NONE; | ||
318 | |||
319 | do { | ||
320 | status = inl(io + SIS_PISR_A); | ||
321 | if (status) { | ||
322 | sis_voice_irq(status, sis->voices); | ||
323 | outl(status, io + SIS_PISR_A); | ||
324 | } | ||
325 | |||
326 | status = inl(io + SIS_PISR_B); | ||
327 | if (status) { | ||
328 | sis_voice_irq(status, &sis->voices[32]); | ||
329 | outl(status, io + SIS_PISR_B); | ||
330 | } | ||
331 | |||
332 | status = inl(io + SIS_RISR); | ||
333 | if (status) { | ||
334 | voice = &sis->capture_voice; | ||
335 | if (!voice->timing) | ||
336 | snd_pcm_period_elapsed(voice->substream); | ||
337 | |||
338 | outl(status, io + SIS_RISR); | ||
339 | } | ||
340 | |||
341 | outl(intr, io + SIS_GISR); | ||
342 | intr = inl(io + SIS_GISR); | ||
343 | intr &= SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS | | ||
344 | SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS; | ||
345 | } while (intr); | ||
346 | |||
347 | return IRQ_HANDLED; | ||
348 | } | ||
349 | |||
350 | static u32 sis_rate_to_delta(unsigned int rate) | ||
351 | { | ||
352 | u32 delta; | ||
353 | |||
354 | /* This was copied from the trident driver, but it seems its gotten | ||
355 | * around a bit... nevertheless, it works well. | ||
356 | * | ||
357 | * We special case 44100 and 8000 since rounding with the equation | ||
358 | * does not give us an accurate enough value. For 11025 and 22050 | ||
359 | * the equation gives us the best answer. All other frequencies will | ||
360 | * also use the equation. JDW | ||
361 | */ | ||
362 | if (rate == 44100) | ||
363 | delta = 0xeb3; | ||
364 | else if (rate == 8000) | ||
365 | delta = 0x2ab; | ||
366 | else if (rate == 48000) | ||
367 | delta = 0x1000; | ||
368 | else | ||
369 | delta = (((rate << 12) + 24000) / 48000) & 0x0000ffff; | ||
370 | return delta; | ||
371 | } | ||
372 | |||
373 | static void __sis_map_silence(struct sis7019 *sis) | ||
374 | { | ||
375 | /* Helper function: must hold sis->voice_lock on entry */ | ||
376 | if (!sis->silence_users) | ||
377 | sis->silence_dma_addr = pci_map_single(sis->pci, | ||
378 | sis->suspend_state[0], | ||
379 | 4096, PCI_DMA_TODEVICE); | ||
380 | sis->silence_users++; | ||
381 | } | ||
382 | |||
383 | static void __sis_unmap_silence(struct sis7019 *sis) | ||
384 | { | ||
385 | /* Helper function: must hold sis->voice_lock on entry */ | ||
386 | sis->silence_users--; | ||
387 | if (!sis->silence_users) | ||
388 | pci_unmap_single(sis->pci, sis->silence_dma_addr, 4096, | ||
389 | PCI_DMA_TODEVICE); | ||
390 | } | ||
391 | |||
392 | static void sis_free_voice(struct sis7019 *sis, struct voice *voice) | ||
393 | { | ||
394 | unsigned long flags; | ||
395 | |||
396 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
397 | if (voice->timing) { | ||
398 | __sis_unmap_silence(sis); | ||
399 | voice->timing->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | | ||
400 | VOICE_SYNC_TIMING); | ||
401 | voice->timing = NULL; | ||
402 | } | ||
403 | voice->flags &= ~(VOICE_IN_USE | VOICE_SSO_TIMING | VOICE_SYNC_TIMING); | ||
404 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
405 | } | ||
406 | |||
407 | static struct voice *__sis_alloc_playback_voice(struct sis7019 *sis) | ||
408 | { | ||
409 | /* Must hold the voice_lock on entry */ | ||
410 | struct voice *voice; | ||
411 | int i; | ||
412 | |||
413 | for (i = 0; i < 64; i++) { | ||
414 | voice = &sis->voices[i]; | ||
415 | if (voice->flags & VOICE_IN_USE) | ||
416 | continue; | ||
417 | voice->flags |= VOICE_IN_USE; | ||
418 | goto found_one; | ||
419 | } | ||
420 | voice = NULL; | ||
421 | |||
422 | found_one: | ||
423 | return voice; | ||
424 | } | ||
425 | |||
426 | static struct voice *sis_alloc_playback_voice(struct sis7019 *sis) | ||
427 | { | ||
428 | struct voice *voice; | ||
429 | unsigned long flags; | ||
430 | |||
431 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
432 | voice = __sis_alloc_playback_voice(sis); | ||
433 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
434 | |||
435 | return voice; | ||
436 | } | ||
437 | |||
438 | static int sis_alloc_timing_voice(struct snd_pcm_substream *substream, | ||
439 | struct snd_pcm_hw_params *hw_params) | ||
440 | { | ||
441 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
442 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
443 | struct voice *voice = runtime->private_data; | ||
444 | unsigned int period_size, buffer_size; | ||
445 | unsigned long flags; | ||
446 | int needed; | ||
447 | |||
448 | /* If there are one or two periods per buffer, we don't need a | ||
449 | * timing voice, as we can use the capture channel's interrupts | ||
450 | * to clock out the periods. | ||
451 | */ | ||
452 | period_size = params_period_size(hw_params); | ||
453 | buffer_size = params_buffer_size(hw_params); | ||
454 | needed = (period_size != buffer_size && | ||
455 | period_size != (buffer_size / 2)); | ||
456 | |||
457 | if (needed && !voice->timing) { | ||
458 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
459 | voice->timing = __sis_alloc_playback_voice(sis); | ||
460 | if (voice->timing) | ||
461 | __sis_map_silence(sis); | ||
462 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
463 | if (!voice->timing) | ||
464 | return -ENOMEM; | ||
465 | voice->timing->substream = substream; | ||
466 | } else if (!needed && voice->timing) { | ||
467 | sis_free_voice(sis, voice); | ||
468 | voice->timing = NULL; | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int sis_playback_open(struct snd_pcm_substream *substream) | ||
475 | { | ||
476 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
477 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
478 | struct voice *voice; | ||
479 | |||
480 | voice = sis_alloc_playback_voice(sis); | ||
481 | if (!voice) | ||
482 | return -EAGAIN; | ||
483 | |||
484 | voice->substream = substream; | ||
485 | runtime->private_data = voice; | ||
486 | runtime->hw = sis_playback_hw_info; | ||
487 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
488 | 9, 0xfff9); | ||
489 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
490 | 9, 0xfff9); | ||
491 | snd_pcm_set_sync(substream); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int sis_substream_close(struct snd_pcm_substream *substream) | ||
496 | { | ||
497 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
498 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
499 | struct voice *voice = runtime->private_data; | ||
500 | |||
501 | sis_free_voice(sis, voice); | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int sis_playback_hw_params(struct snd_pcm_substream *substream, | ||
506 | struct snd_pcm_hw_params *hw_params) | ||
507 | { | ||
508 | return snd_pcm_lib_malloc_pages(substream, | ||
509 | params_buffer_bytes(hw_params)); | ||
510 | } | ||
511 | |||
512 | static int sis_hw_free(struct snd_pcm_substream *substream) | ||
513 | { | ||
514 | return snd_pcm_lib_free_pages(substream); | ||
515 | } | ||
516 | |||
517 | static int sis_pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
518 | { | ||
519 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
520 | struct voice *voice = runtime->private_data; | ||
521 | void __iomem *ctrl_base = voice->ctrl_base; | ||
522 | void __iomem *wave_base = voice->wave_base; | ||
523 | u32 format, dma_addr, control, sso_eso, delta, reg; | ||
524 | u16 leo; | ||
525 | |||
526 | /* We rely on the PCM core to ensure that the parameters for this | ||
527 | * substream do not change on us while we're programming the HW. | ||
528 | */ | ||
529 | format = 0; | ||
530 | if (snd_pcm_format_width(runtime->format) == 8) | ||
531 | format |= SIS_PLAY_DMA_FORMAT_8BIT; | ||
532 | if (!snd_pcm_format_signed(runtime->format)) | ||
533 | format |= SIS_PLAY_DMA_FORMAT_UNSIGNED; | ||
534 | if (runtime->channels == 1) | ||
535 | format |= SIS_PLAY_DMA_FORMAT_MONO; | ||
536 | |||
537 | /* The baseline setup is for a single period per buffer, and | ||
538 | * we add bells and whistles as needed from there. | ||
539 | */ | ||
540 | dma_addr = runtime->dma_addr; | ||
541 | leo = runtime->buffer_size - 1; | ||
542 | control = leo | SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_LEO; | ||
543 | sso_eso = leo; | ||
544 | |||
545 | if (runtime->period_size == (runtime->buffer_size / 2)) { | ||
546 | control |= SIS_PLAY_DMA_INTR_AT_MLP; | ||
547 | } else if (runtime->period_size != runtime->buffer_size) { | ||
548 | voice->flags |= VOICE_SSO_TIMING; | ||
549 | voice->sso = runtime->period_size - 1; | ||
550 | voice->period_size = runtime->period_size; | ||
551 | voice->buffer_size = runtime->buffer_size; | ||
552 | |||
553 | control &= ~SIS_PLAY_DMA_INTR_AT_LEO; | ||
554 | control |= SIS_PLAY_DMA_INTR_AT_SSO; | ||
555 | sso_eso |= (runtime->period_size - 1) << 16; | ||
556 | } | ||
557 | |||
558 | delta = sis_rate_to_delta(runtime->rate); | ||
559 | |||
560 | /* Ok, we're ready to go, set up the channel. | ||
561 | */ | ||
562 | writel(format, ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
563 | writel(dma_addr, ctrl_base + SIS_PLAY_DMA_BASE); | ||
564 | writel(control, ctrl_base + SIS_PLAY_DMA_CONTROL); | ||
565 | writel(sso_eso, ctrl_base + SIS_PLAY_DMA_SSO_ESO); | ||
566 | |||
567 | for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) | ||
568 | writel(0, wave_base + reg); | ||
569 | |||
570 | writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); | ||
571 | writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); | ||
572 | writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | | ||
573 | SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | | ||
574 | SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, | ||
575 | wave_base + SIS_WAVE_CHANNEL_CONTROL); | ||
576 | |||
577 | /* Force PCI writes to post. */ | ||
578 | readl(ctrl_base); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int sis_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
584 | { | ||
585 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
586 | unsigned long io = sis->ioport; | ||
587 | struct snd_pcm_substream *s; | ||
588 | struct voice *voice; | ||
589 | void *chip; | ||
590 | int starting; | ||
591 | u32 record = 0; | ||
592 | u32 play[2] = { 0, 0 }; | ||
593 | |||
594 | /* No locks needed, as the PCM core will hold the locks on the | ||
595 | * substreams, and the HW will only start/stop the indicated voices | ||
596 | * without changing the state of the others. | ||
597 | */ | ||
598 | switch (cmd) { | ||
599 | case SNDRV_PCM_TRIGGER_START: | ||
600 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
601 | case SNDRV_PCM_TRIGGER_RESUME: | ||
602 | starting = 1; | ||
603 | break; | ||
604 | case SNDRV_PCM_TRIGGER_STOP: | ||
605 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
606 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
607 | starting = 0; | ||
608 | break; | ||
609 | default: | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | snd_pcm_group_for_each_entry(s, substream) { | ||
614 | /* Make sure it is for us... */ | ||
615 | chip = snd_pcm_substream_chip(s); | ||
616 | if (chip != sis) | ||
617 | continue; | ||
618 | |||
619 | voice = s->runtime->private_data; | ||
620 | if (voice->flags & VOICE_CAPTURE) { | ||
621 | record |= 1 << voice->num; | ||
622 | voice = voice->timing; | ||
623 | } | ||
624 | |||
625 | /* voice could be NULL if this a recording stream, and it | ||
626 | * doesn't have an external timing channel. | ||
627 | */ | ||
628 | if (voice) | ||
629 | play[voice->num / 32] |= 1 << (voice->num & 0x1f); | ||
630 | |||
631 | snd_pcm_trigger_done(s, substream); | ||
632 | } | ||
633 | |||
634 | if (starting) { | ||
635 | if (record) | ||
636 | outl(record, io + SIS_RECORD_START_REG); | ||
637 | if (play[0]) | ||
638 | outl(play[0], io + SIS_PLAY_START_A_REG); | ||
639 | if (play[1]) | ||
640 | outl(play[1], io + SIS_PLAY_START_B_REG); | ||
641 | } else { | ||
642 | if (record) | ||
643 | outl(record, io + SIS_RECORD_STOP_REG); | ||
644 | if (play[0]) | ||
645 | outl(play[0], io + SIS_PLAY_STOP_A_REG); | ||
646 | if (play[1]) | ||
647 | outl(play[1], io + SIS_PLAY_STOP_B_REG); | ||
648 | } | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static snd_pcm_uframes_t sis_pcm_pointer(struct snd_pcm_substream *substream) | ||
653 | { | ||
654 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
655 | struct voice *voice = runtime->private_data; | ||
656 | u32 cso; | ||
657 | |||
658 | cso = readl(voice->ctrl_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
659 | cso &= 0xffff; | ||
660 | return cso; | ||
661 | } | ||
662 | |||
663 | static int sis_capture_open(struct snd_pcm_substream *substream) | ||
664 | { | ||
665 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
666 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
667 | struct voice *voice = &sis->capture_voice; | ||
668 | unsigned long flags; | ||
669 | |||
670 | /* FIXME: The driver only supports recording from one channel | ||
671 | * at the moment, but it could support more. | ||
672 | */ | ||
673 | spin_lock_irqsave(&sis->voice_lock, flags); | ||
674 | if (voice->flags & VOICE_IN_USE) | ||
675 | voice = NULL; | ||
676 | else | ||
677 | voice->flags |= VOICE_IN_USE; | ||
678 | spin_unlock_irqrestore(&sis->voice_lock, flags); | ||
679 | |||
680 | if (!voice) | ||
681 | return -EAGAIN; | ||
682 | |||
683 | voice->substream = substream; | ||
684 | runtime->private_data = voice; | ||
685 | runtime->hw = sis_capture_hw_info; | ||
686 | runtime->hw.rates = sis->ac97[0]->rates[AC97_RATES_ADC]; | ||
687 | snd_pcm_limit_hw_rates(runtime); | ||
688 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
689 | 9, 0xfff9); | ||
690 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
691 | 9, 0xfff9); | ||
692 | snd_pcm_set_sync(substream); | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | static int sis_capture_hw_params(struct snd_pcm_substream *substream, | ||
697 | struct snd_pcm_hw_params *hw_params) | ||
698 | { | ||
699 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
700 | int rc; | ||
701 | |||
702 | rc = snd_ac97_set_rate(sis->ac97[0], AC97_PCM_LR_ADC_RATE, | ||
703 | params_rate(hw_params)); | ||
704 | if (rc) | ||
705 | goto out; | ||
706 | |||
707 | rc = snd_pcm_lib_malloc_pages(substream, | ||
708 | params_buffer_bytes(hw_params)); | ||
709 | if (rc < 0) | ||
710 | goto out; | ||
711 | |||
712 | rc = sis_alloc_timing_voice(substream, hw_params); | ||
713 | |||
714 | out: | ||
715 | return rc; | ||
716 | } | ||
717 | |||
718 | static void sis_prepare_timing_voice(struct voice *voice, | ||
719 | struct snd_pcm_substream *substream) | ||
720 | { | ||
721 | struct sis7019 *sis = snd_pcm_substream_chip(substream); | ||
722 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
723 | struct voice *timing = voice->timing; | ||
724 | void __iomem *play_base = timing->ctrl_base; | ||
725 | void __iomem *wave_base = timing->wave_base; | ||
726 | u16 buffer_size, period_size; | ||
727 | u32 format, control, sso_eso, delta; | ||
728 | u32 vperiod, sso, reg; | ||
729 | |||
730 | /* Set our initial buffer and period as large as we can given a | ||
731 | * single page of silence. | ||
732 | */ | ||
733 | buffer_size = 4096 / runtime->channels; | ||
734 | buffer_size /= snd_pcm_format_size(runtime->format, 1); | ||
735 | period_size = buffer_size; | ||
736 | |||
737 | /* Initially, we want to interrupt just a bit behind the end of | ||
738 | * the period we're clocking out. 10 samples seems to give a good | ||
739 | * delay. | ||
740 | * | ||
741 | * We want to spread our interrupts throughout the virtual period, | ||
742 | * so that we don't end up with two interrupts back to back at the | ||
743 | * end -- this helps minimize the effects of any jitter. Adjust our | ||
744 | * clocking period size so that the last period is at least a fourth | ||
745 | * of a full period. | ||
746 | * | ||
747 | * This is all moot if we don't need to use virtual periods. | ||
748 | */ | ||
749 | vperiod = runtime->period_size + 10; | ||
750 | if (vperiod > period_size) { | ||
751 | u16 tail = vperiod % period_size; | ||
752 | u16 quarter_period = period_size / 4; | ||
753 | |||
754 | if (tail && tail < quarter_period) { | ||
755 | u16 loops = vperiod / period_size; | ||
756 | |||
757 | tail = quarter_period - tail; | ||
758 | tail += loops - 1; | ||
759 | tail /= loops; | ||
760 | period_size -= tail; | ||
761 | } | ||
762 | |||
763 | sso = period_size - 1; | ||
764 | } else { | ||
765 | /* The initial period will fit inside the buffer, so we | ||
766 | * don't need to use virtual periods -- disable them. | ||
767 | */ | ||
768 | period_size = runtime->period_size; | ||
769 | sso = vperiod - 1; | ||
770 | vperiod = 0; | ||
771 | } | ||
772 | |||
773 | /* The interrupt handler implements the timing syncronization, so | ||
774 | * setup its state. | ||
775 | */ | ||
776 | timing->flags |= VOICE_SYNC_TIMING; | ||
777 | timing->sync_base = voice->ctrl_base; | ||
778 | timing->sync_cso = runtime->period_size - 1; | ||
779 | timing->sync_period_size = runtime->period_size; | ||
780 | timing->sync_buffer_size = runtime->buffer_size; | ||
781 | timing->period_size = period_size; | ||
782 | timing->buffer_size = buffer_size; | ||
783 | timing->sso = sso; | ||
784 | timing->vperiod = vperiod; | ||
785 | |||
786 | /* Using unsigned samples with the all-zero silence buffer | ||
787 | * forces the output to the lower rail, killing playback. | ||
788 | * So ignore unsigned vs signed -- it doesn't change the timing. | ||
789 | */ | ||
790 | format = 0; | ||
791 | if (snd_pcm_format_width(runtime->format) == 8) | ||
792 | format = SIS_CAPTURE_DMA_FORMAT_8BIT; | ||
793 | if (runtime->channels == 1) | ||
794 | format |= SIS_CAPTURE_DMA_FORMAT_MONO; | ||
795 | |||
796 | control = timing->buffer_size - 1; | ||
797 | control |= SIS_PLAY_DMA_LOOP | SIS_PLAY_DMA_INTR_AT_SSO; | ||
798 | sso_eso = timing->buffer_size - 1; | ||
799 | sso_eso |= timing->sso << 16; | ||
800 | |||
801 | delta = sis_rate_to_delta(runtime->rate); | ||
802 | |||
803 | /* We've done the math, now configure the channel. | ||
804 | */ | ||
805 | writel(format, play_base + SIS_PLAY_DMA_FORMAT_CSO); | ||
806 | writel(sis->silence_dma_addr, play_base + SIS_PLAY_DMA_BASE); | ||
807 | writel(control, play_base + SIS_PLAY_DMA_CONTROL); | ||
808 | writel(sso_eso, play_base + SIS_PLAY_DMA_SSO_ESO); | ||
809 | |||
810 | for (reg = 0; reg < SIS_WAVE_SIZE; reg += 4) | ||
811 | writel(0, wave_base + reg); | ||
812 | |||
813 | writel(SIS_WAVE_GENERAL_WAVE_VOLUME, wave_base + SIS_WAVE_GENERAL); | ||
814 | writel(delta << 16, wave_base + SIS_WAVE_GENERAL_ARTICULATION); | ||
815 | writel(SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE | | ||
816 | SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE | | ||
817 | SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE, | ||
818 | wave_base + SIS_WAVE_CHANNEL_CONTROL); | ||
819 | } | ||
820 | |||
821 | static int sis_pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
822 | { | ||
823 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
824 | struct voice *voice = runtime->private_data; | ||
825 | void __iomem *rec_base = voice->ctrl_base; | ||
826 | u32 format, dma_addr, control; | ||
827 | u16 leo; | ||
828 | |||
829 | /* We rely on the PCM core to ensure that the parameters for this | ||
830 | * substream do not change on us while we're programming the HW. | ||
831 | */ | ||
832 | format = 0; | ||
833 | if (snd_pcm_format_width(runtime->format) == 8) | ||
834 | format = SIS_CAPTURE_DMA_FORMAT_8BIT; | ||
835 | if (!snd_pcm_format_signed(runtime->format)) | ||
836 | format |= SIS_CAPTURE_DMA_FORMAT_UNSIGNED; | ||
837 | if (runtime->channels == 1) | ||
838 | format |= SIS_CAPTURE_DMA_FORMAT_MONO; | ||
839 | |||
840 | dma_addr = runtime->dma_addr; | ||
841 | leo = runtime->buffer_size - 1; | ||
842 | control = leo | SIS_CAPTURE_DMA_LOOP; | ||
843 | |||
844 | /* If we've got more than two periods per buffer, then we have | ||
845 | * use a timing voice to clock out the periods. Otherwise, we can | ||
846 | * use the capture channel's interrupts. | ||
847 | */ | ||
848 | if (voice->timing) { | ||
849 | sis_prepare_timing_voice(voice, substream); | ||
850 | } else { | ||
851 | control |= SIS_CAPTURE_DMA_INTR_AT_LEO; | ||
852 | if (runtime->period_size != runtime->buffer_size) | ||
853 | control |= SIS_CAPTURE_DMA_INTR_AT_MLP; | ||
854 | } | ||
855 | |||
856 | writel(format, rec_base + SIS_CAPTURE_DMA_FORMAT_CSO); | ||
857 | writel(dma_addr, rec_base + SIS_CAPTURE_DMA_BASE); | ||
858 | writel(control, rec_base + SIS_CAPTURE_DMA_CONTROL); | ||
859 | |||
860 | /* Force the writes to post. */ | ||
861 | readl(rec_base); | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static struct snd_pcm_ops sis_playback_ops = { | ||
867 | .open = sis_playback_open, | ||
868 | .close = sis_substream_close, | ||
869 | .ioctl = snd_pcm_lib_ioctl, | ||
870 | .hw_params = sis_playback_hw_params, | ||
871 | .hw_free = sis_hw_free, | ||
872 | .prepare = sis_pcm_playback_prepare, | ||
873 | .trigger = sis_pcm_trigger, | ||
874 | .pointer = sis_pcm_pointer, | ||
875 | }; | ||
876 | |||
877 | static struct snd_pcm_ops sis_capture_ops = { | ||
878 | .open = sis_capture_open, | ||
879 | .close = sis_substream_close, | ||
880 | .ioctl = snd_pcm_lib_ioctl, | ||
881 | .hw_params = sis_capture_hw_params, | ||
882 | .hw_free = sis_hw_free, | ||
883 | .prepare = sis_pcm_capture_prepare, | ||
884 | .trigger = sis_pcm_trigger, | ||
885 | .pointer = sis_pcm_pointer, | ||
886 | }; | ||
887 | |||
888 | static int __devinit sis_pcm_create(struct sis7019 *sis) | ||
889 | { | ||
890 | struct snd_pcm *pcm; | ||
891 | int rc; | ||
892 | |||
893 | /* We have 64 voices, and the driver currently records from | ||
894 | * only one channel, though that could change in the future. | ||
895 | */ | ||
896 | rc = snd_pcm_new(sis->card, "SiS7019", 0, 64, 1, &pcm); | ||
897 | if (rc) | ||
898 | return rc; | ||
899 | |||
900 | pcm->private_data = sis; | ||
901 | strcpy(pcm->name, "SiS7019"); | ||
902 | sis->pcm = pcm; | ||
903 | |||
904 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sis_playback_ops); | ||
905 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &sis_capture_ops); | ||
906 | |||
907 | /* Try to preallocate some memory, but it's not the end of the | ||
908 | * world if this fails. | ||
909 | */ | ||
910 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
911 | snd_dma_pci_data(sis->pci), 64*1024, 128*1024); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static unsigned short sis_ac97_rw(struct sis7019 *sis, int codec, u32 cmd) | ||
917 | { | ||
918 | unsigned long io = sis->ioport; | ||
919 | unsigned short val = 0xffff; | ||
920 | u16 status; | ||
921 | u16 rdy; | ||
922 | int count; | ||
923 | const static u16 codec_ready[3] = { | ||
924 | SIS_AC97_STATUS_CODEC_READY, | ||
925 | SIS_AC97_STATUS_CODEC2_READY, | ||
926 | SIS_AC97_STATUS_CODEC3_READY, | ||
927 | }; | ||
928 | |||
929 | rdy = codec_ready[codec]; | ||
930 | |||
931 | |||
932 | /* Get the AC97 semaphore -- software first, so we don't spin | ||
933 | * pounding out IO reads on the hardware semaphore... | ||
934 | */ | ||
935 | mutex_lock(&sis->ac97_mutex); | ||
936 | |||
937 | count = 0xffff; | ||
938 | while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) | ||
939 | udelay(1); | ||
940 | |||
941 | if (!count) | ||
942 | goto timeout; | ||
943 | |||
944 | /* ... and wait for any outstanding commands to complete ... | ||
945 | */ | ||
946 | count = 0xffff; | ||
947 | do { | ||
948 | status = inw(io + SIS_AC97_STATUS); | ||
949 | if ((status & rdy) && !(status & SIS_AC97_STATUS_BUSY)) | ||
950 | break; | ||
951 | |||
952 | udelay(1); | ||
953 | } while (--count); | ||
954 | |||
955 | if (!count) | ||
956 | goto timeout_sema; | ||
957 | |||
958 | /* ... before sending our command and waiting for it to finish ... | ||
959 | */ | ||
960 | outl(cmd, io + SIS_AC97_CMD); | ||
961 | udelay(10); | ||
962 | |||
963 | count = 0xffff; | ||
964 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) | ||
965 | udelay(1); | ||
966 | |||
967 | /* ... and reading the results (if any). | ||
968 | */ | ||
969 | val = inl(io + SIS_AC97_CMD) >> 16; | ||
970 | |||
971 | timeout_sema: | ||
972 | outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); | ||
973 | timeout: | ||
974 | mutex_unlock(&sis->ac97_mutex); | ||
975 | |||
976 | if (!count) { | ||
977 | printk(KERN_ERR "sis7019: ac97 codec %d timeout cmd 0x%08x\n", | ||
978 | codec, cmd); | ||
979 | } | ||
980 | |||
981 | return val; | ||
982 | } | ||
983 | |||
984 | static void sis_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
985 | unsigned short val) | ||
986 | { | ||
987 | const static u32 cmd[3] = { | ||
988 | SIS_AC97_CMD_CODEC_WRITE, | ||
989 | SIS_AC97_CMD_CODEC2_WRITE, | ||
990 | SIS_AC97_CMD_CODEC3_WRITE, | ||
991 | }; | ||
992 | sis_ac97_rw(ac97->private_data, ac97->num, | ||
993 | (val << 16) | (reg << 8) | cmd[ac97->num]); | ||
994 | } | ||
995 | |||
996 | static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | ||
997 | { | ||
998 | const static u32 cmd[3] = { | ||
999 | SIS_AC97_CMD_CODEC_READ, | ||
1000 | SIS_AC97_CMD_CODEC2_READ, | ||
1001 | SIS_AC97_CMD_CODEC3_READ, | ||
1002 | }; | ||
1003 | return sis_ac97_rw(ac97->private_data, ac97->num, | ||
1004 | (reg << 8) | cmd[ac97->num]); | ||
1005 | } | ||
1006 | |||
1007 | static int __devinit sis_mixer_create(struct sis7019 *sis) | ||
1008 | { | ||
1009 | struct snd_ac97_bus *bus; | ||
1010 | struct snd_ac97_template ac97; | ||
1011 | static struct snd_ac97_bus_ops ops = { | ||
1012 | .write = sis_ac97_write, | ||
1013 | .read = sis_ac97_read, | ||
1014 | }; | ||
1015 | int rc; | ||
1016 | |||
1017 | memset(&ac97, 0, sizeof(ac97)); | ||
1018 | ac97.private_data = sis; | ||
1019 | |||
1020 | rc = snd_ac97_bus(sis->card, 0, &ops, NULL, &bus); | ||
1021 | if (!rc && sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1022 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[0]); | ||
1023 | ac97.num = 1; | ||
1024 | if (!rc && (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT)) | ||
1025 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[1]); | ||
1026 | ac97.num = 2; | ||
1027 | if (!rc && (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT)) | ||
1028 | rc = snd_ac97_mixer(bus, &ac97, &sis->ac97[2]); | ||
1029 | |||
1030 | /* If we return an error here, then snd_card_free() should | ||
1031 | * free up any ac97 codecs that got created, as well as the bus. | ||
1032 | */ | ||
1033 | return rc; | ||
1034 | } | ||
1035 | |||
1036 | static void sis_free_suspend(struct sis7019 *sis) | ||
1037 | { | ||
1038 | int i; | ||
1039 | |||
1040 | for (i = 0; i < SIS_SUSPEND_PAGES; i++) | ||
1041 | kfree(sis->suspend_state[i]); | ||
1042 | } | ||
1043 | |||
1044 | static int sis_chip_free(struct sis7019 *sis) | ||
1045 | { | ||
1046 | /* Reset the chip, and disable all interrputs. | ||
1047 | */ | ||
1048 | outl(SIS_GCR_SOFTWARE_RESET, sis->ioport + SIS_GCR); | ||
1049 | udelay(10); | ||
1050 | outl(0, sis->ioport + SIS_GCR); | ||
1051 | outl(0, sis->ioport + SIS_GIER); | ||
1052 | |||
1053 | /* Now, free everything we allocated. | ||
1054 | */ | ||
1055 | if (sis->irq >= 0) | ||
1056 | free_irq(sis->irq, sis); | ||
1057 | |||
1058 | if (sis->ioaddr) | ||
1059 | iounmap(sis->ioaddr); | ||
1060 | |||
1061 | pci_release_regions(sis->pci); | ||
1062 | pci_disable_device(sis->pci); | ||
1063 | |||
1064 | sis_free_suspend(sis); | ||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | static int sis_dev_free(struct snd_device *dev) | ||
1069 | { | ||
1070 | struct sis7019 *sis = dev->device_data; | ||
1071 | return sis_chip_free(sis); | ||
1072 | } | ||
1073 | |||
1074 | static int sis_chip_init(struct sis7019 *sis) | ||
1075 | { | ||
1076 | unsigned long io = sis->ioport; | ||
1077 | void __iomem *ioaddr = sis->ioaddr; | ||
1078 | u16 status; | ||
1079 | int count; | ||
1080 | int i; | ||
1081 | |||
1082 | /* Reset the audio controller | ||
1083 | */ | ||
1084 | outl(SIS_GCR_SOFTWARE_RESET, io + SIS_GCR); | ||
1085 | udelay(10); | ||
1086 | outl(0, io + SIS_GCR); | ||
1087 | |||
1088 | /* Get the AC-link semaphore, and reset the codecs | ||
1089 | */ | ||
1090 | count = 0xffff; | ||
1091 | while ((inw(io + SIS_AC97_SEMA) & SIS_AC97_SEMA_BUSY) && --count) | ||
1092 | udelay(1); | ||
1093 | |||
1094 | if (!count) | ||
1095 | return -EIO; | ||
1096 | |||
1097 | outl(SIS_AC97_CMD_CODEC_COLD_RESET, io + SIS_AC97_CMD); | ||
1098 | udelay(10); | ||
1099 | |||
1100 | count = 0xffff; | ||
1101 | while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) | ||
1102 | udelay(1); | ||
1103 | |||
1104 | /* Now that we've finished the reset, find out what's attached. | ||
1105 | */ | ||
1106 | status = inl(io + SIS_AC97_STATUS); | ||
1107 | if (status & SIS_AC97_STATUS_CODEC_READY) | ||
1108 | sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; | ||
1109 | if (status & SIS_AC97_STATUS_CODEC2_READY) | ||
1110 | sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; | ||
1111 | if (status & SIS_AC97_STATUS_CODEC3_READY) | ||
1112 | sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; | ||
1113 | |||
1114 | /* All done, let go of the semaphore, and check for errors | ||
1115 | */ | ||
1116 | outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); | ||
1117 | if (!sis->codecs_present || !count) | ||
1118 | return -EIO; | ||
1119 | |||
1120 | /* Let the hardware know that the audio driver is alive, | ||
1121 | * and enable PCM slots on the AC-link for L/R playback (3 & 4) and | ||
1122 | * record channels. We're going to want to use Variable Rate Audio | ||
1123 | * for recording, to avoid needlessly resampling from 48kHZ. | ||
1124 | */ | ||
1125 | outl(SIS_AC97_CONF_AUDIO_ALIVE, io + SIS_AC97_CONF); | ||
1126 | outl(SIS_AC97_CONF_AUDIO_ALIVE | SIS_AC97_CONF_PCM_LR_ENABLE | | ||
1127 | SIS_AC97_CONF_PCM_CAP_MIC_ENABLE | | ||
1128 | SIS_AC97_CONF_PCM_CAP_LR_ENABLE | | ||
1129 | SIS_AC97_CONF_CODEC_VRA_ENABLE, io + SIS_AC97_CONF); | ||
1130 | |||
1131 | /* All AC97 PCM slots should be sourced from sub-mixer 0. | ||
1132 | */ | ||
1133 | outl(0, io + SIS_AC97_PSR); | ||
1134 | |||
1135 | /* There is only one valid DMA setup for a PCI environment. | ||
1136 | */ | ||
1137 | outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); | ||
1138 | |||
1139 | /* Reset the syncronization groups for all of the channels | ||
1140 | * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. | ||
1141 | * we'll need to change how we handle these. Until then, we just | ||
1142 | * assign sub-mixer 0 to all playback channels, and avoid any | ||
1143 | * attenuation on the audio. | ||
1144 | */ | ||
1145 | outl(0, io + SIS_PLAY_SYNC_GROUP_A); | ||
1146 | outl(0, io + SIS_PLAY_SYNC_GROUP_B); | ||
1147 | outl(0, io + SIS_PLAY_SYNC_GROUP_C); | ||
1148 | outl(0, io + SIS_PLAY_SYNC_GROUP_D); | ||
1149 | outl(0, io + SIS_MIXER_SYNC_GROUP); | ||
1150 | |||
1151 | for (i = 0; i < 64; i++) { | ||
1152 | writel(i, SIS_MIXER_START_ADDR(ioaddr, i)); | ||
1153 | writel(SIS_MIXER_RIGHT_NO_ATTEN | SIS_MIXER_LEFT_NO_ATTEN | | ||
1154 | SIS_MIXER_DEST_0, SIS_MIXER_ADDR(ioaddr, i)); | ||
1155 | } | ||
1156 | |||
1157 | /* Don't attenuate any audio set for the wave amplifier. | ||
1158 | * | ||
1159 | * FIXME: Maximum attenuation is set for the music amp, which will | ||
1160 | * need to change if we start using the synth engine. | ||
1161 | */ | ||
1162 | outl(0xffff0000, io + SIS_WEVCR); | ||
1163 | |||
1164 | /* Ensure that the wave engine is in normal operating mode. | ||
1165 | */ | ||
1166 | outl(0, io + SIS_WECCR); | ||
1167 | |||
1168 | /* Go ahead and enable the DMA interrupts. They won't go live | ||
1169 | * until we start a channel. | ||
1170 | */ | ||
1171 | outl(SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE | | ||
1172 | SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE, io + SIS_GIER); | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | #ifdef CONFIG_PM | ||
1178 | static int sis_suspend(struct pci_dev *pci, pm_message_t state) | ||
1179 | { | ||
1180 | struct snd_card *card = pci_get_drvdata(pci); | ||
1181 | struct sis7019 *sis = card->private_data; | ||
1182 | void __iomem *ioaddr = sis->ioaddr; | ||
1183 | int i; | ||
1184 | |||
1185 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
1186 | snd_pcm_suspend_all(sis->pcm); | ||
1187 | if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1188 | snd_ac97_suspend(sis->ac97[0]); | ||
1189 | if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) | ||
1190 | snd_ac97_suspend(sis->ac97[1]); | ||
1191 | if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) | ||
1192 | snd_ac97_suspend(sis->ac97[2]); | ||
1193 | |||
1194 | /* snd_pcm_suspend_all() stopped all channels, so we're quiescent. | ||
1195 | */ | ||
1196 | if (sis->irq >= 0) { | ||
1197 | synchronize_irq(sis->irq); | ||
1198 | free_irq(sis->irq, sis); | ||
1199 | sis->irq = -1; | ||
1200 | } | ||
1201 | |||
1202 | /* Save the internal state away | ||
1203 | */ | ||
1204 | for (i = 0; i < 4; i++) { | ||
1205 | memcpy_fromio(sis->suspend_state[i], ioaddr, 4096); | ||
1206 | ioaddr += 4096; | ||
1207 | } | ||
1208 | |||
1209 | pci_disable_device(pci); | ||
1210 | pci_save_state(pci); | ||
1211 | pci_set_power_state(pci, pci_choose_state(pci, state)); | ||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static int sis_resume(struct pci_dev *pci) | ||
1216 | { | ||
1217 | struct snd_card *card = pci_get_drvdata(pci); | ||
1218 | struct sis7019 *sis = card->private_data; | ||
1219 | void __iomem *ioaddr = sis->ioaddr; | ||
1220 | int i; | ||
1221 | |||
1222 | pci_set_power_state(pci, PCI_D0); | ||
1223 | pci_restore_state(pci); | ||
1224 | |||
1225 | if (pci_enable_device(pci) < 0) { | ||
1226 | printk(KERN_ERR "sis7019: unable to re-enable device\n"); | ||
1227 | goto error; | ||
1228 | } | ||
1229 | |||
1230 | if (sis_chip_init(sis)) { | ||
1231 | printk(KERN_ERR "sis7019: unable to re-init controller\n"); | ||
1232 | goto error; | ||
1233 | } | ||
1234 | |||
1235 | if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1236 | card->shortname, sis)) { | ||
1237 | printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq); | ||
1238 | goto error; | ||
1239 | } | ||
1240 | |||
1241 | /* Restore saved state, then clear out the page we use for the | ||
1242 | * silence buffer. | ||
1243 | */ | ||
1244 | for (i = 0; i < 4; i++) { | ||
1245 | memcpy_toio(ioaddr, sis->suspend_state[i], 4096); | ||
1246 | ioaddr += 4096; | ||
1247 | } | ||
1248 | |||
1249 | memset(sis->suspend_state[0], 0, 4096); | ||
1250 | |||
1251 | sis->irq = pci->irq; | ||
1252 | pci_set_master(pci); | ||
1253 | |||
1254 | if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT) | ||
1255 | snd_ac97_resume(sis->ac97[0]); | ||
1256 | if (sis->codecs_present & SIS_SECONDARY_CODEC_PRESENT) | ||
1257 | snd_ac97_resume(sis->ac97[1]); | ||
1258 | if (sis->codecs_present & SIS_TERTIARY_CODEC_PRESENT) | ||
1259 | snd_ac97_resume(sis->ac97[2]); | ||
1260 | |||
1261 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
1262 | return 0; | ||
1263 | |||
1264 | error: | ||
1265 | snd_card_disconnect(card); | ||
1266 | return -EIO; | ||
1267 | } | ||
1268 | #endif /* CONFIG_PM */ | ||
1269 | |||
1270 | static int sis_alloc_suspend(struct sis7019 *sis) | ||
1271 | { | ||
1272 | int i; | ||
1273 | |||
1274 | /* We need 16K to store the internal wave engine state during a | ||
1275 | * suspend, but we don't need it to be contiguous, so play nice | ||
1276 | * with the memory system. We'll also use this area for a silence | ||
1277 | * buffer. | ||
1278 | */ | ||
1279 | for (i = 0; i < SIS_SUSPEND_PAGES; i++) { | ||
1280 | sis->suspend_state[i] = kmalloc(4096, GFP_KERNEL); | ||
1281 | if (!sis->suspend_state[i]) | ||
1282 | return -ENOMEM; | ||
1283 | } | ||
1284 | memset(sis->suspend_state[0], 0, 4096); | ||
1285 | |||
1286 | return 0; | ||
1287 | } | ||
1288 | |||
1289 | static int __devinit sis_chip_create(struct snd_card *card, | ||
1290 | struct pci_dev *pci) | ||
1291 | { | ||
1292 | struct sis7019 *sis = card->private_data; | ||
1293 | struct voice *voice; | ||
1294 | static struct snd_device_ops ops = { | ||
1295 | .dev_free = sis_dev_free, | ||
1296 | }; | ||
1297 | int rc; | ||
1298 | int i; | ||
1299 | |||
1300 | rc = pci_enable_device(pci); | ||
1301 | if (rc) | ||
1302 | goto error_out; | ||
1303 | |||
1304 | if (pci_set_dma_mask(pci, DMA_30BIT_MASK) < 0) { | ||
1305 | printk(KERN_ERR "sis7019: architecture does not support " | ||
1306 | "30-bit PCI busmaster DMA"); | ||
1307 | goto error_out_enabled; | ||
1308 | } | ||
1309 | |||
1310 | memset(sis, 0, sizeof(*sis)); | ||
1311 | mutex_init(&sis->ac97_mutex); | ||
1312 | spin_lock_init(&sis->voice_lock); | ||
1313 | sis->card = card; | ||
1314 | sis->pci = pci; | ||
1315 | sis->irq = -1; | ||
1316 | sis->ioport = pci_resource_start(pci, 0); | ||
1317 | |||
1318 | rc = pci_request_regions(pci, "SiS7019"); | ||
1319 | if (rc) { | ||
1320 | printk(KERN_ERR "sis7019: unable request regions\n"); | ||
1321 | goto error_out_enabled; | ||
1322 | } | ||
1323 | |||
1324 | rc = -EIO; | ||
1325 | sis->ioaddr = ioremap_nocache(pci_resource_start(pci, 1), 0x4000); | ||
1326 | if (!sis->ioaddr) { | ||
1327 | printk(KERN_ERR "sis7019: unable to remap MMIO, aborting\n"); | ||
1328 | goto error_out_cleanup; | ||
1329 | } | ||
1330 | |||
1331 | rc = sis_alloc_suspend(sis); | ||
1332 | if (rc < 0) { | ||
1333 | printk(KERN_ERR "sis7019: unable to allocate state storage\n"); | ||
1334 | goto error_out_cleanup; | ||
1335 | } | ||
1336 | |||
1337 | rc = sis_chip_init(sis); | ||
1338 | if (rc) | ||
1339 | goto error_out_cleanup; | ||
1340 | |||
1341 | if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED, | ||
1342 | card->shortname, sis)) { | ||
1343 | printk(KERN_ERR "unable to allocate irq %d\n", sis->irq); | ||
1344 | goto error_out_cleanup; | ||
1345 | } | ||
1346 | |||
1347 | sis->irq = pci->irq; | ||
1348 | pci_set_master(pci); | ||
1349 | |||
1350 | for (i = 0; i < 64; i++) { | ||
1351 | voice = &sis->voices[i]; | ||
1352 | voice->num = i; | ||
1353 | voice->ctrl_base = SIS_PLAY_DMA_ADDR(sis->ioaddr, i); | ||
1354 | voice->wave_base = SIS_WAVE_ADDR(sis->ioaddr, i); | ||
1355 | } | ||
1356 | |||
1357 | voice = &sis->capture_voice; | ||
1358 | voice->flags = VOICE_CAPTURE; | ||
1359 | voice->num = SIS_CAPTURE_CHAN_AC97_PCM_IN; | ||
1360 | voice->ctrl_base = SIS_CAPTURE_DMA_ADDR(sis->ioaddr, voice->num); | ||
1361 | |||
1362 | rc = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sis, &ops); | ||
1363 | if (rc) | ||
1364 | goto error_out_cleanup; | ||
1365 | |||
1366 | snd_card_set_dev(card, &pci->dev); | ||
1367 | |||
1368 | return 0; | ||
1369 | |||
1370 | error_out_cleanup: | ||
1371 | sis_chip_free(sis); | ||
1372 | |||
1373 | error_out_enabled: | ||
1374 | pci_disable_device(pci); | ||
1375 | |||
1376 | error_out: | ||
1377 | return rc; | ||
1378 | } | ||
1379 | |||
1380 | static int __devinit snd_sis7019_probe(struct pci_dev *pci, | ||
1381 | const struct pci_device_id *pci_id) | ||
1382 | { | ||
1383 | struct snd_card *card; | ||
1384 | struct sis7019 *sis; | ||
1385 | int rc; | ||
1386 | |||
1387 | rc = -ENOENT; | ||
1388 | if (!enable) | ||
1389 | goto error_out; | ||
1390 | |||
1391 | rc = -ENOMEM; | ||
1392 | card = snd_card_new(index, id, THIS_MODULE, sizeof(*sis)); | ||
1393 | if (!card) | ||
1394 | goto error_out; | ||
1395 | |||
1396 | strcpy(card->driver, "SiS7019"); | ||
1397 | strcpy(card->shortname, "SiS7019"); | ||
1398 | rc = sis_chip_create(card, pci); | ||
1399 | if (rc) | ||
1400 | goto card_error_out; | ||
1401 | |||
1402 | sis = card->private_data; | ||
1403 | |||
1404 | rc = sis_mixer_create(sis); | ||
1405 | if (rc) | ||
1406 | goto card_error_out; | ||
1407 | |||
1408 | rc = sis_pcm_create(sis); | ||
1409 | if (rc) | ||
1410 | goto card_error_out; | ||
1411 | |||
1412 | snprintf(card->longname, sizeof(card->longname), | ||
1413 | "%s Audio Accelerator with %s at 0x%lx, irq %d", | ||
1414 | card->shortname, snd_ac97_get_short_name(sis->ac97[0]), | ||
1415 | sis->ioport, sis->irq); | ||
1416 | |||
1417 | rc = snd_card_register(card); | ||
1418 | if (rc) | ||
1419 | goto card_error_out; | ||
1420 | |||
1421 | pci_set_drvdata(pci, card); | ||
1422 | return 0; | ||
1423 | |||
1424 | card_error_out: | ||
1425 | snd_card_free(card); | ||
1426 | |||
1427 | error_out: | ||
1428 | return rc; | ||
1429 | } | ||
1430 | |||
1431 | static void __devexit snd_sis7019_remove(struct pci_dev *pci) | ||
1432 | { | ||
1433 | snd_card_free(pci_get_drvdata(pci)); | ||
1434 | pci_set_drvdata(pci, NULL); | ||
1435 | } | ||
1436 | |||
1437 | static struct pci_driver sis7019_driver = { | ||
1438 | .name = "SiS7019", | ||
1439 | .id_table = snd_sis7019_ids, | ||
1440 | .probe = snd_sis7019_probe, | ||
1441 | .remove = __devexit_p(snd_sis7019_remove), | ||
1442 | |||
1443 | #ifdef CONFIG_PM | ||
1444 | .suspend = sis_suspend, | ||
1445 | .resume = sis_resume, | ||
1446 | #endif | ||
1447 | }; | ||
1448 | |||
1449 | static int __init sis7019_init(void) | ||
1450 | { | ||
1451 | return pci_register_driver(&sis7019_driver); | ||
1452 | } | ||
1453 | |||
1454 | static void __exit sis7019_exit(void) | ||
1455 | { | ||
1456 | pci_unregister_driver(&sis7019_driver); | ||
1457 | } | ||
1458 | |||
1459 | module_init(sis7019_init); | ||
1460 | module_exit(sis7019_exit); | ||
diff --git a/sound/pci/sis7019.h b/sound/pci/sis7019.h new file mode 100644 index 000000000000..013b6739a742 --- /dev/null +++ b/sound/pci/sis7019.h | |||
@@ -0,0 +1,342 @@ | |||
1 | #ifndef __sis7019_h__ | ||
2 | #define __sis7019_h__ | ||
3 | |||
4 | /* | ||
5 | * Definitions for SiS7019 Audio Accelerator | ||
6 | * | ||
7 | * Copyright (C) 2004-2007, David Dillow | ||
8 | * Written by David Dillow <dave@thedillows.org> | ||
9 | * Inspired by the Trident 4D-WaveDX/NX driver. | ||
10 | * | ||
11 | * All rights reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation, version 2. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | |||
28 | /* General Control Register */ | ||
29 | #define SIS_GCR 0x00 | ||
30 | #define SIS_GCR_MACRO_POWER_DOWN 0x80000000 | ||
31 | #define SIS_GCR_MODEM_ENABLE 0x00010000 | ||
32 | #define SIS_GCR_SOFTWARE_RESET 0x00000001 | ||
33 | |||
34 | /* General Interrupt Enable Register */ | ||
35 | #define SIS_GIER 0x04 | ||
36 | #define SIS_GIER_MODEM_TIMER_IRQ_ENABLE 0x00100000 | ||
37 | #define SIS_GIER_MODEM_RX_DMA_IRQ_ENABLE 0x00080000 | ||
38 | #define SIS_GIER_MODEM_TX_DMA_IRQ_ENABLE 0x00040000 | ||
39 | #define SIS_GIER_AC97_GPIO1_IRQ_ENABLE 0x00020000 | ||
40 | #define SIS_GIER_AC97_GPIO0_IRQ_ENABLE 0x00010000 | ||
41 | #define SIS_GIER_AC97_SAMPLE_TIMER_IRQ_ENABLE 0x00000010 | ||
42 | #define SIS_GIER_AUDIO_GLOBAL_TIMER_IRQ_ENABLE 0x00000008 | ||
43 | #define SIS_GIER_AUDIO_RECORD_DMA_IRQ_ENABLE 0x00000004 | ||
44 | #define SIS_GIER_AUDIO_PLAY_DMA_IRQ_ENABLE 0x00000002 | ||
45 | #define SIS_GIER_AUDIO_WAVE_ENGINE_IRQ_ENABLE 0x00000001 | ||
46 | |||
47 | /* General Interrupt Status Register */ | ||
48 | #define SIS_GISR 0x08 | ||
49 | #define SIS_GISR_MODEM_TIMER_IRQ_STATUS 0x00100000 | ||
50 | #define SIS_GISR_MODEM_RX_DMA_IRQ_STATUS 0x00080000 | ||
51 | #define SIS_GISR_MODEM_TX_DMA_IRQ_STATUS 0x00040000 | ||
52 | #define SIS_GISR_AC97_GPIO1_IRQ_STATUS 0x00020000 | ||
53 | #define SIS_GISR_AC97_GPIO0_IRQ_STATUS 0x00010000 | ||
54 | #define SIS_GISR_AC97_SAMPLE_TIMER_IRQ_STATUS 0x00000010 | ||
55 | #define SIS_GISR_AUDIO_GLOBAL_TIMER_IRQ_STATUS 0x00000008 | ||
56 | #define SIS_GISR_AUDIO_RECORD_DMA_IRQ_STATUS 0x00000004 | ||
57 | #define SIS_GISR_AUDIO_PLAY_DMA_IRQ_STATUS 0x00000002 | ||
58 | #define SIS_GISR_AUDIO_WAVE_ENGINE_IRQ_STATUS 0x00000001 | ||
59 | |||
60 | /* DMA Control Register */ | ||
61 | #define SIS_DMA_CSR 0x10 | ||
62 | #define SIS_DMA_CSR_PCI_SETTINGS 0x0000001d | ||
63 | #define SIS_DMA_CSR_CONCURRENT_ENABLE 0x00000200 | ||
64 | #define SIS_DMA_CSR_PIPELINE_ENABLE 0x00000100 | ||
65 | #define SIS_DMA_CSR_RX_DRAIN_ENABLE 0x00000010 | ||
66 | #define SIS_DMA_CSR_RX_FILL_ENABLE 0x00000008 | ||
67 | #define SIS_DMA_CSR_TX_DRAIN_ENABLE 0x00000004 | ||
68 | #define SIS_DMA_CSR_TX_LOWPRI_FILL_ENABLE 0x00000002 | ||
69 | #define SIS_DMA_CSR_TX_HIPRI_FILL_ENABLE 0x00000001 | ||
70 | |||
71 | /* Playback Channel Start Registers */ | ||
72 | #define SIS_PLAY_START_A_REG 0x14 | ||
73 | #define SIS_PLAY_START_B_REG 0x18 | ||
74 | |||
75 | /* Playback Channel Stop Registers */ | ||
76 | #define SIS_PLAY_STOP_A_REG 0x1c | ||
77 | #define SIS_PLAY_STOP_B_REG 0x20 | ||
78 | |||
79 | /* Recording Channel Start Register */ | ||
80 | #define SIS_RECORD_START_REG 0x24 | ||
81 | |||
82 | /* Recording Channel Stop Register */ | ||
83 | #define SIS_RECORD_STOP_REG 0x28 | ||
84 | |||
85 | /* Playback Interrupt Status Registers */ | ||
86 | #define SIS_PISR_A 0x2c | ||
87 | #define SIS_PISR_B 0x30 | ||
88 | |||
89 | /* Recording Interrupt Status Register */ | ||
90 | #define SIS_RISR 0x34 | ||
91 | |||
92 | /* AC97 AC-link Playback Source Register */ | ||
93 | #define SIS_AC97_PSR 0x40 | ||
94 | #define SIS_AC97_PSR_MODEM_HEADSET_SRC_MIXER 0x0f000000 | ||
95 | #define SIS_AC97_PSR_MODEM_LINE2_SRC_MIXER 0x00f00000 | ||
96 | #define SIS_AC97_PSR_MODEM_LINE1_SRC_MIXER 0x000f0000 | ||
97 | #define SIS_AC97_PSR_PCM_LFR_SRC_MIXER 0x0000f000 | ||
98 | #define SIS_AC97_PSR_PCM_SURROUND_SRC_MIXER 0x00000f00 | ||
99 | #define SIS_AC97_PSR_PCM_CENTER_SRC_MIXER 0x000000f0 | ||
100 | #define SIS_AC97_PSR_PCM_LR_SRC_MIXER 0x0000000f | ||
101 | |||
102 | /* AC97 AC-link Command Register */ | ||
103 | #define SIS_AC97_CMD 0x50 | ||
104 | #define SIS_AC97_CMD_DATA_MASK 0xffff0000 | ||
105 | #define SIS_AC97_CMD_REG_MASK 0x0000ff00 | ||
106 | #define SIS_AC97_CMD_CODEC3_READ 0x0000000d | ||
107 | #define SIS_AC97_CMD_CODEC3_WRITE 0x0000000c | ||
108 | #define SIS_AC97_CMD_CODEC2_READ 0x0000000b | ||
109 | #define SIS_AC97_CMD_CODEC2_WRITE 0x0000000a | ||
110 | #define SIS_AC97_CMD_CODEC_READ 0x00000009 | ||
111 | #define SIS_AC97_CMD_CODEC_WRITE 0x00000008 | ||
112 | #define SIS_AC97_CMD_CODEC_WARM_RESET 0x00000005 | ||
113 | #define SIS_AC97_CMD_CODEC_COLD_RESET 0x00000004 | ||
114 | #define SIS_AC97_CMD_DONE 0x00000000 | ||
115 | |||
116 | /* AC97 AC-link Semaphore Register */ | ||
117 | #define SIS_AC97_SEMA 0x54 | ||
118 | #define SIS_AC97_SEMA_BUSY 0x00000001 | ||
119 | #define SIS_AC97_SEMA_RELEASE 0x00000000 | ||
120 | |||
121 | /* AC97 AC-link Status Register */ | ||
122 | #define SIS_AC97_STATUS 0x58 | ||
123 | #define SIS_AC97_STATUS_AUDIO_D2_INACT_SECS 0x03f00000 | ||
124 | #define SIS_AC97_STATUS_MODEM_ALIVE 0x00002000 | ||
125 | #define SIS_AC97_STATUS_AUDIO_ALIVE 0x00001000 | ||
126 | #define SIS_AC97_STATUS_CODEC3_READY 0x00000400 | ||
127 | #define SIS_AC97_STATUS_CODEC2_READY 0x00000200 | ||
128 | #define SIS_AC97_STATUS_CODEC_READY 0x00000100 | ||
129 | #define SIS_AC97_STATUS_WARM_RESET 0x00000080 | ||
130 | #define SIS_AC97_STATUS_COLD_RESET 0x00000040 | ||
131 | #define SIS_AC97_STATUS_POWERED_DOWN 0x00000020 | ||
132 | #define SIS_AC97_STATUS_NORMAL 0x00000010 | ||
133 | #define SIS_AC97_STATUS_READ_EXPIRED 0x00000004 | ||
134 | #define SIS_AC97_STATUS_SEMAPHORE 0x00000002 | ||
135 | #define SIS_AC97_STATUS_BUSY 0x00000001 | ||
136 | |||
137 | /* AC97 AC-link Audio Configuration Register */ | ||
138 | #define SIS_AC97_CONF 0x5c | ||
139 | #define SIS_AC97_CONF_AUDIO_ALIVE 0x80000000 | ||
140 | #define SIS_AC97_CONF_WARM_RESET_ENABLE 0x40000000 | ||
141 | #define SIS_AC97_CONF_PR6_ENABLE 0x20000000 | ||
142 | #define SIS_AC97_CONF_PR5_ENABLE 0x10000000 | ||
143 | #define SIS_AC97_CONF_PR4_ENABLE 0x08000000 | ||
144 | #define SIS_AC97_CONF_PR3_ENABLE 0x04000000 | ||
145 | #define SIS_AC97_CONF_PR2_PR7_ENABLE 0x02000000 | ||
146 | #define SIS_AC97_CONF_PR0_PR1_ENABLE 0x01000000 | ||
147 | #define SIS_AC97_CONF_AUTO_PM_ENABLE 0x00800000 | ||
148 | #define SIS_AC97_CONF_PCM_LFE_ENABLE 0x00080000 | ||
149 | #define SIS_AC97_CONF_PCM_SURROUND_ENABLE 0x00040000 | ||
150 | #define SIS_AC97_CONF_PCM_CENTER_ENABLE 0x00020000 | ||
151 | #define SIS_AC97_CONF_PCM_LR_ENABLE 0x00010000 | ||
152 | #define SIS_AC97_CONF_PCM_CAP_MIC_ENABLE 0x00002000 | ||
153 | #define SIS_AC97_CONF_PCM_CAP_LR_ENABLE 0x00001000 | ||
154 | #define SIS_AC97_CONF_PCM_CAP_MIC_FROM_CODEC3 0x00000200 | ||
155 | #define SIS_AC97_CONF_PCM_CAP_LR_FROM_CODEC3 0x00000100 | ||
156 | #define SIS_AC97_CONF_CODEC3_PM_VRM 0x00000080 | ||
157 | #define SIS_AC97_CONF_CODEC_PM_VRM 0x00000040 | ||
158 | #define SIS_AC97_CONF_CODEC3_VRA_ENABLE 0x00000020 | ||
159 | #define SIS_AC97_CONF_CODEC_VRA_ENABLE 0x00000010 | ||
160 | #define SIS_AC97_CONF_CODEC3_PM_EAC 0x00000008 | ||
161 | #define SIS_AC97_CONF_CODEC_PM_EAC 0x00000004 | ||
162 | #define SIS_AC97_CONF_CODEC3_EXISTS 0x00000002 | ||
163 | #define SIS_AC97_CONF_CODEC_EXISTS 0x00000001 | ||
164 | |||
165 | /* Playback Channel Sync Group registers */ | ||
166 | #define SIS_PLAY_SYNC_GROUP_A 0x80 | ||
167 | #define SIS_PLAY_SYNC_GROUP_B 0x84 | ||
168 | #define SIS_PLAY_SYNC_GROUP_C 0x88 | ||
169 | #define SIS_PLAY_SYNC_GROUP_D 0x8c | ||
170 | #define SIS_MIXER_SYNC_GROUP 0x90 | ||
171 | |||
172 | /* Wave Engine Config and Control Register */ | ||
173 | #define SIS_WECCR 0xa0 | ||
174 | #define SIS_WECCR_TESTMODE_MASK 0x00300000 | ||
175 | #define SIS_WECCR_TESTMODE_NORMAL 0x00000000 | ||
176 | #define SIS_WECCR_TESTMODE_BYPASS_NSO_ALPHA 0x00100000 | ||
177 | #define SIS_WECCR_TESTMODE_BYPASS_FC 0x00200000 | ||
178 | #define SIS_WECCR_TESTMODE_BYPASS_WOL 0x00300000 | ||
179 | #define SIS_WECCR_RESONANCE_DELAY_MASK 0x00060000 | ||
180 | #define SIS_WECCR_RESONANCE_DELAY_NONE 0x00000000 | ||
181 | #define SIS_WECCR_RESONANCE_DELAY_FC_1F00 0x00020000 | ||
182 | #define SIS_WECCR_RESONANCE_DELAY_FC_1E00 0x00040000 | ||
183 | #define SIS_WECCR_RESONANCE_DELAY_FC_1C00 0x00060000 | ||
184 | #define SIS_WECCR_IGNORE_CHANNEL_PARMS 0x00010000 | ||
185 | #define SIS_WECCR_COMMAND_CHANNEL_ID_MASK 0x0003ff00 | ||
186 | #define SIS_WECCR_COMMAND_MASK 0x00000007 | ||
187 | #define SIS_WECCR_COMMAND_NONE 0x00000000 | ||
188 | #define SIS_WECCR_COMMAND_DONE 0x00000000 | ||
189 | #define SIS_WECCR_COMMAND_PAUSE 0x00000001 | ||
190 | #define SIS_WECCR_COMMAND_TOGGLE_VEG 0x00000002 | ||
191 | #define SIS_WECCR_COMMAND_TOGGLE_MEG 0x00000003 | ||
192 | #define SIS_WECCR_COMMAND_TOGGLE_VEG_MEG 0x00000004 | ||
193 | |||
194 | /* Wave Engine Volume Control Register */ | ||
195 | #define SIS_WEVCR 0xa4 | ||
196 | #define SIS_WEVCR_LEFT_MUSIC_ATTENUATION_MASK 0xff000000 | ||
197 | #define SIS_WEVCR_RIGHT_MUSIC_ATTENUATION_MASK 0x00ff0000 | ||
198 | #define SIS_WEVCR_LEFT_WAVE_ATTENUATION_MASK 0x0000ff00 | ||
199 | #define SIS_WEVCR_RIGHT_WAVE_ATTENUATION_MASK 0x000000ff | ||
200 | |||
201 | /* Wave Engine Interrupt Status Registers */ | ||
202 | #define SIS_WEISR_A 0xa8 | ||
203 | #define SIS_WEISR_B 0xac | ||
204 | |||
205 | |||
206 | /* Playback DMA parameters (paramter RAM) */ | ||
207 | #define SIS_PLAY_DMA_OFFSET 0x0000 | ||
208 | #define SIS_PLAY_DMA_SIZE 0x10 | ||
209 | #define SIS_PLAY_DMA_ADDR(addr, num) \ | ||
210 | ((num * SIS_PLAY_DMA_SIZE) + (addr) + SIS_PLAY_DMA_OFFSET) | ||
211 | |||
212 | #define SIS_PLAY_DMA_FORMAT_CSO 0x00 | ||
213 | #define SIS_PLAY_DMA_FORMAT_UNSIGNED 0x00080000 | ||
214 | #define SIS_PLAY_DMA_FORMAT_8BIT 0x00040000 | ||
215 | #define SIS_PLAY_DMA_FORMAT_MONO 0x00020000 | ||
216 | #define SIS_PLAY_DMA_CSO_MASK 0x0000ffff | ||
217 | #define SIS_PLAY_DMA_BASE 0x04 | ||
218 | #define SIS_PLAY_DMA_CONTROL 0x08 | ||
219 | #define SIS_PLAY_DMA_STOP_AT_SSO 0x04000000 | ||
220 | #define SIS_PLAY_DMA_RELEASE 0x02000000 | ||
221 | #define SIS_PLAY_DMA_LOOP 0x01000000 | ||
222 | #define SIS_PLAY_DMA_INTR_AT_SSO 0x00080000 | ||
223 | #define SIS_PLAY_DMA_INTR_AT_ESO 0x00040000 | ||
224 | #define SIS_PLAY_DMA_INTR_AT_LEO 0x00020000 | ||
225 | #define SIS_PLAY_DMA_INTR_AT_MLP 0x00010000 | ||
226 | #define SIS_PLAY_DMA_LEO_MASK 0x0000ffff | ||
227 | #define SIS_PLAY_DMA_SSO_ESO 0x0c | ||
228 | #define SIS_PLAY_DMA_SSO_MASK 0xffff0000 | ||
229 | #define SIS_PLAY_DMA_ESO_MASK 0x0000ffff | ||
230 | |||
231 | /* Capture DMA parameters (paramter RAM) */ | ||
232 | #define SIS_CAPTURE_DMA_OFFSET 0x0800 | ||
233 | #define SIS_CAPTURE_DMA_SIZE 0x10 | ||
234 | #define SIS_CAPTURE_DMA_ADDR(addr, num) \ | ||
235 | ((num * SIS_CAPTURE_DMA_SIZE) + (addr) + SIS_CAPTURE_DMA_OFFSET) | ||
236 | |||
237 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_0 0 | ||
238 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_1 1 | ||
239 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_2 2 | ||
240 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_3 3 | ||
241 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_4 4 | ||
242 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_5 5 | ||
243 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_6 6 | ||
244 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_7 7 | ||
245 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_8 8 | ||
246 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_9 9 | ||
247 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_10 10 | ||
248 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_11 11 | ||
249 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_12 12 | ||
250 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_13 13 | ||
251 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_14 14 | ||
252 | #define SIS_CAPTURE_CHAN_MIXER_ROUTE_BACK_15 15 | ||
253 | #define SIS_CAPTURE_CHAN_AC97_PCM_IN 16 | ||
254 | #define SIS_CAPTURE_CHAN_AC97_MIC_IN 17 | ||
255 | #define SIS_CAPTURE_CHAN_AC97_LINE1_IN 18 | ||
256 | #define SIS_CAPTURE_CHAN_AC97_LINE2_IN 19 | ||
257 | #define SIS_CAPTURE_CHAN_AC97_HANDSE_IN 20 | ||
258 | |||
259 | #define SIS_CAPTURE_DMA_FORMAT_CSO 0x00 | ||
260 | #define SIS_CAPTURE_DMA_MONO_MODE_MASK 0xc0000000 | ||
261 | #define SIS_CAPTURE_DMA_MONO_MODE_AVG 0x00000000 | ||
262 | #define SIS_CAPTURE_DMA_MONO_MODE_LEFT 0x40000000 | ||
263 | #define SIS_CAPTURE_DMA_MONO_MODE_RIGHT 0x80000000 | ||
264 | #define SIS_CAPTURE_DMA_FORMAT_UNSIGNED 0x00080000 | ||
265 | #define SIS_CAPTURE_DMA_FORMAT_8BIT 0x00040000 | ||
266 | #define SIS_CAPTURE_DMA_FORMAT_MONO 0x00020000 | ||
267 | #define SIS_CAPTURE_DMA_CSO_MASK 0x0000ffff | ||
268 | #define SIS_CAPTURE_DMA_BASE 0x04 | ||
269 | #define SIS_CAPTURE_DMA_CONTROL 0x08 | ||
270 | #define SIS_CAPTURE_DMA_STOP_AT_SSO 0x04000000 | ||
271 | #define SIS_CAPTURE_DMA_RELEASE 0x02000000 | ||
272 | #define SIS_CAPTURE_DMA_LOOP 0x01000000 | ||
273 | #define SIS_CAPTURE_DMA_INTR_AT_LEO 0x00020000 | ||
274 | #define SIS_CAPTURE_DMA_INTR_AT_MLP 0x00010000 | ||
275 | #define SIS_CAPTURE_DMA_LEO_MASK 0x0000ffff | ||
276 | #define SIS_CAPTURE_DMA_RESERVED 0x0c | ||
277 | |||
278 | |||
279 | /* Mixer routing list start pointer (parameter RAM) */ | ||
280 | #define SIS_MIXER_START_OFFSET 0x1000 | ||
281 | #define SIS_MIXER_START_SIZE 0x04 | ||
282 | #define SIS_MIXER_START_ADDR(addr, num) \ | ||
283 | ((num * SIS_MIXER_START_SIZE) + (addr) + SIS_MIXER_START_OFFSET) | ||
284 | |||
285 | #define SIS_MIXER_START_MASK 0x0000007f | ||
286 | |||
287 | /* Mixer routing table (parameter RAM) */ | ||
288 | #define SIS_MIXER_OFFSET 0x1400 | ||
289 | #define SIS_MIXER_SIZE 0x04 | ||
290 | #define SIS_MIXER_ADDR(addr, num) \ | ||
291 | ((num * SIS_MIXER_SIZE) + (addr) + SIS_MIXER_OFFSET) | ||
292 | |||
293 | #define SIS_MIXER_RIGHT_ATTENUTATION_MASK 0xff000000 | ||
294 | #define SIS_MIXER_RIGHT_NO_ATTEN 0xff000000 | ||
295 | #define SIS_MIXER_LEFT_ATTENUTATION_MASK 0x00ff0000 | ||
296 | #define SIS_MIXER_LEFT_NO_ATTEN 0x00ff0000 | ||
297 | #define SIS_MIXER_NEXT_ENTRY_MASK 0x00007f00 | ||
298 | #define SIS_MIXER_NEXT_ENTRY_NONE 0x00000000 | ||
299 | #define SIS_MIXER_DEST_MASK 0x0000007f | ||
300 | #define SIS_MIXER_DEST_0 0x00000020 | ||
301 | #define SIS_MIXER_DEST_1 0x00000021 | ||
302 | #define SIS_MIXER_DEST_2 0x00000022 | ||
303 | #define SIS_MIXER_DEST_3 0x00000023 | ||
304 | #define SIS_MIXER_DEST_4 0x00000024 | ||
305 | #define SIS_MIXER_DEST_5 0x00000025 | ||
306 | #define SIS_MIXER_DEST_6 0x00000026 | ||
307 | #define SIS_MIXER_DEST_7 0x00000027 | ||
308 | #define SIS_MIXER_DEST_8 0x00000028 | ||
309 | #define SIS_MIXER_DEST_9 0x00000029 | ||
310 | #define SIS_MIXER_DEST_10 0x0000002a | ||
311 | #define SIS_MIXER_DEST_11 0x0000002b | ||
312 | #define SIS_MIXER_DEST_12 0x0000002c | ||
313 | #define SIS_MIXER_DEST_13 0x0000002d | ||
314 | #define SIS_MIXER_DEST_14 0x0000002e | ||
315 | #define SIS_MIXER_DEST_15 0x0000002f | ||
316 | |||
317 | /* Wave Engine Control Parameters (parameter RAM) */ | ||
318 | #define SIS_WAVE_OFFSET 0x2000 | ||
319 | #define SIS_WAVE_SIZE 0x40 | ||
320 | #define SIS_WAVE_ADDR(addr, num) \ | ||
321 | ((num * SIS_WAVE_SIZE) + (addr) + SIS_WAVE_OFFSET) | ||
322 | |||
323 | #define SIS_WAVE_GENERAL 0x00 | ||
324 | #define SIS_WAVE_GENERAL_WAVE_VOLUME 0x80000000 | ||
325 | #define SIS_WAVE_GENERAL_MUSIC_VOLUME 0x00000000 | ||
326 | #define SIS_WAVE_GENERAL_VOLUME_MASK 0x7f000000 | ||
327 | #define SIS_WAVE_GENERAL_ARTICULATION 0x04 | ||
328 | #define SIS_WAVE_GENERAL_ARTICULATION_DELTA_MASK 0x3fff0000 | ||
329 | #define SIS_WAVE_ARTICULATION 0x08 | ||
330 | #define SIS_WAVE_TIMER 0x0c | ||
331 | #define SIS_WAVE_GENERATOR 0x10 | ||
332 | #define SIS_WAVE_CHANNEL_CONTROL 0x14 | ||
333 | #define SIS_WAVE_CHANNEL_CONTROL_FIRST_SAMPLE 0x80000000 | ||
334 | #define SIS_WAVE_CHANNEL_CONTROL_AMP_ENABLE 0x40000000 | ||
335 | #define SIS_WAVE_CHANNEL_CONTROL_FILTER_ENABLE 0x20000000 | ||
336 | #define SIS_WAVE_CHANNEL_CONTROL_INTERPOLATE_ENABLE 0x10000000 | ||
337 | #define SIS_WAVE_LFO_EG_CONTROL 0x18 | ||
338 | #define SIS_WAVE_LFO_EG_CONTROL_2 0x1c | ||
339 | #define SIS_WAVE_LFO_EG_CONTROL_3 0x20 | ||
340 | #define SIS_WAVE_LFO_EG_CONTROL_4 0x24 | ||
341 | |||
342 | #endif /* __sis7019_h__ */ | ||
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 44a7f5fad573..0d3d305b0a0b 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <sound/driver.h> | ||
26 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile index 65f2c218324c..88676b50f385 100644 --- a/sound/pci/trident/Makefile +++ b/sound/pci/trident/Makefile | |||
@@ -4,16 +4,6 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | snd-trident-objs := trident.o trident_main.o trident_memory.o | 6 | snd-trident-objs := trident.o trident_main.o trident_memory.o |
7 | snd-trident-synth-objs := trident_synth.o | ||
8 | |||
9 | # | ||
10 | # this function returns: | ||
11 | # "m" - CONFIG_SND_SEQUENCER is m | ||
12 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
13 | # otherwise parameter #1 value | ||
14 | # | ||
15 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
16 | 7 | ||
17 | # Toplevel Module Dependency | 8 | # Toplevel Module Dependency |
18 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o | 9 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o |
19 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-trident-synth.o | ||
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 84884567df6a..d94b16ffb385 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <sound/driver.h> | ||
25 | #include <linux/init.h> | 24 | #include <linux/init.h> |
26 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
27 | #include <linux/time.h> | 26 | #include <linux/time.h> |
@@ -155,13 +154,6 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, | |||
155 | return err; | 154 | return err; |
156 | } | 155 | } |
157 | 156 | ||
158 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
159 | if ((err = snd_trident_attach_synthesizer(trident)) < 0) { | ||
160 | snd_card_free(card); | ||
161 | return err; | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | snd_trident_create_gameport(trident); | 157 | snd_trident_create_gameport(trident); |
166 | 158 | ||
167 | if ((err = snd_card_register(card)) < 0) { | 159 | if ((err = snd_card_register(card)) < 0) { |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index a235e034a690..71138ff9b310 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -27,7 +27,6 @@ | |||
27 | * SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net> | 27 | * SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net> |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <sound/driver.h> | ||
31 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
33 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
@@ -436,7 +435,7 @@ static void snd_trident_free_synth_channel(struct snd_trident *trident, int chan | |||
436 | Description: This routine will complete and write the 5 hardware channel | 435 | Description: This routine will complete and write the 5 hardware channel |
437 | registers to hardware. | 436 | registers to hardware. |
438 | 437 | ||
439 | Paramters: trident - pointer to target device class for 4DWave. | 438 | Parameters: trident - pointer to target device class for 4DWave. |
440 | voice - synthesizer voice structure | 439 | voice - synthesizer voice structure |
441 | Each register field. | 440 | Each register field. |
442 | 441 | ||
@@ -514,7 +513,7 @@ EXPORT_SYMBOL(snd_trident_write_voice_regs); | |||
514 | Description: This routine will write the new CSO offset | 513 | Description: This routine will write the new CSO offset |
515 | register to hardware. | 514 | register to hardware. |
516 | 515 | ||
517 | Paramters: trident - pointer to target device class for 4DWave. | 516 | Parameters: trident - pointer to target device class for 4DWave. |
518 | voice - synthesizer voice structure | 517 | voice - synthesizer voice structure |
519 | CSO - new CSO value | 518 | CSO - new CSO value |
520 | 519 | ||
@@ -540,7 +539,7 @@ static void snd_trident_write_cso_reg(struct snd_trident * trident, | |||
540 | Description: This routine will write the new ESO offset | 539 | Description: This routine will write the new ESO offset |
541 | register to hardware. | 540 | register to hardware. |
542 | 541 | ||
543 | Paramters: trident - pointer to target device class for 4DWave. | 542 | Parameters: trident - pointer to target device class for 4DWave. |
544 | voice - synthesizer voice structure | 543 | voice - synthesizer voice structure |
545 | ESO - new ESO value | 544 | ESO - new ESO value |
546 | 545 | ||
@@ -566,7 +565,7 @@ static void snd_trident_write_eso_reg(struct snd_trident * trident, | |||
566 | Description: This routine will write the new voice volume | 565 | Description: This routine will write the new voice volume |
567 | register to hardware. | 566 | register to hardware. |
568 | 567 | ||
569 | Paramters: trident - pointer to target device class for 4DWave. | 568 | Parameters: trident - pointer to target device class for 4DWave. |
570 | voice - synthesizer voice structure | 569 | voice - synthesizer voice structure |
571 | Vol - new voice volume | 570 | Vol - new voice volume |
572 | 571 | ||
@@ -597,7 +596,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident, | |||
597 | Description: This routine will write the new voice pan | 596 | Description: This routine will write the new voice pan |
598 | register to hardware. | 597 | register to hardware. |
599 | 598 | ||
600 | Paramters: trident - pointer to target device class for 4DWave. | 599 | Parameters: trident - pointer to target device class for 4DWave. |
601 | voice - synthesizer voice structure | 600 | voice - synthesizer voice structure |
602 | Pan - new pan value | 601 | Pan - new pan value |
603 | 602 | ||
@@ -619,7 +618,7 @@ static void snd_trident_write_pan_reg(struct snd_trident * trident, | |||
619 | Description: This routine will write the new reverb volume | 618 | Description: This routine will write the new reverb volume |
620 | register to hardware. | 619 | register to hardware. |
621 | 620 | ||
622 | Paramters: trident - pointer to target device class for 4DWave. | 621 | Parameters: trident - pointer to target device class for 4DWave. |
623 | voice - synthesizer voice structure | 622 | voice - synthesizer voice structure |
624 | RVol - new reverb volume | 623 | RVol - new reverb volume |
625 | 624 | ||
@@ -643,7 +642,7 @@ static void snd_trident_write_rvol_reg(struct snd_trident * trident, | |||
643 | Description: This routine will write the new chorus volume | 642 | Description: This routine will write the new chorus volume |
644 | register to hardware. | 643 | register to hardware. |
645 | 644 | ||
646 | Paramters: trident - pointer to target device class for 4DWave. | 645 | Parameters: trident - pointer to target device class for 4DWave. |
647 | voice - synthesizer voice structure | 646 | voice - synthesizer voice structure |
648 | CVol - new chorus volume | 647 | CVol - new chorus volume |
649 | 648 | ||
@@ -666,7 +665,7 @@ static void snd_trident_write_cvol_reg(struct snd_trident * trident, | |||
666 | 665 | ||
667 | Description: This routine converts rate in HZ to hardware delta value. | 666 | Description: This routine converts rate in HZ to hardware delta value. |
668 | 667 | ||
669 | Paramters: trident - pointer to target device class for 4DWave. | 668 | Parameters: trident - pointer to target device class for 4DWave. |
670 | rate - Real or Virtual channel number. | 669 | rate - Real or Virtual channel number. |
671 | 670 | ||
672 | Returns: Delta value. | 671 | Returns: Delta value. |
@@ -696,7 +695,7 @@ static unsigned int snd_trident_convert_rate(unsigned int rate) | |||
696 | 695 | ||
697 | Description: This routine converts rate in HZ to hardware delta value. | 696 | Description: This routine converts rate in HZ to hardware delta value. |
698 | 697 | ||
699 | Paramters: trident - pointer to target device class for 4DWave. | 698 | Parameters: trident - pointer to target device class for 4DWave. |
700 | rate - Real or Virtual channel number. | 699 | rate - Real or Virtual channel number. |
701 | 700 | ||
702 | Returns: Delta value. | 701 | Returns: Delta value. |
@@ -726,7 +725,7 @@ static unsigned int snd_trident_convert_adc_rate(unsigned int rate) | |||
726 | 725 | ||
727 | Description: This routine converts rate in HZ to spurious threshold. | 726 | Description: This routine converts rate in HZ to spurious threshold. |
728 | 727 | ||
729 | Paramters: trident - pointer to target device class for 4DWave. | 728 | Parameters: trident - pointer to target device class for 4DWave. |
730 | rate - Real or Virtual channel number. | 729 | rate - Real or Virtual channel number. |
731 | 730 | ||
732 | Returns: Delta value. | 731 | Returns: Delta value. |
@@ -748,7 +747,7 @@ static unsigned int snd_trident_spurious_threshold(unsigned int rate, | |||
748 | 747 | ||
749 | Description: This routine returns a control mode for a PCM channel. | 748 | Description: This routine returns a control mode for a PCM channel. |
750 | 749 | ||
751 | Paramters: trident - pointer to target device class for 4DWave. | 750 | Parameters: trident - pointer to target device class for 4DWave. |
752 | substream - PCM substream | 751 | substream - PCM substream |
753 | 752 | ||
754 | Returns: Control value. | 753 | Returns: Control value. |
@@ -781,7 +780,7 @@ static unsigned int snd_trident_control_mode(struct snd_pcm_substream *substream | |||
781 | 780 | ||
782 | Description: Device I/O control handler for playback/capture parameters. | 781 | Description: Device I/O control handler for playback/capture parameters. |
783 | 782 | ||
784 | Paramters: substream - PCM substream class | 783 | Parameters: substream - PCM substream class |
785 | cmd - what ioctl message to process | 784 | cmd - what ioctl message to process |
786 | arg - additional message infoarg | 785 | arg - additional message infoarg |
787 | 786 | ||
@@ -1664,7 +1663,7 @@ static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream * | |||
1664 | 1663 | ||
1665 | Description: This routine return the capture position | 1664 | Description: This routine return the capture position |
1666 | 1665 | ||
1667 | Paramters: pcm1 - PCM device class | 1666 | Parameters: pcm1 - PCM device class |
1668 | 1667 | ||
1669 | Returns: position of buffer | 1668 | Returns: position of buffer |
1670 | 1669 | ||
@@ -2157,7 +2156,7 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { | |||
2157 | 2156 | ||
2158 | Description: This routine registers the 4DWave device for PCM support. | 2157 | Description: This routine registers the 4DWave device for PCM support. |
2159 | 2158 | ||
2160 | Paramters: trident - pointer to target device class for 4DWave. | 2159 | Parameters: trident - pointer to target device class for 4DWave. |
2161 | 2160 | ||
2162 | Returns: None | 2161 | Returns: None |
2163 | 2162 | ||
@@ -2215,7 +2214,7 @@ int __devinit snd_trident_pcm(struct snd_trident * trident, | |||
2215 | 2214 | ||
2216 | Description: This routine registers the 4DWave device for foldback PCM support. | 2215 | Description: This routine registers the 4DWave device for foldback PCM support. |
2217 | 2216 | ||
2218 | Paramters: trident - pointer to target device class for 4DWave. | 2217 | Parameters: trident - pointer to target device class for 4DWave. |
2219 | 2218 | ||
2220 | Returns: None | 2219 | Returns: None |
2221 | 2220 | ||
@@ -2272,7 +2271,7 @@ int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, | |||
2272 | 2271 | ||
2273 | Description: This routine registers the 4DWave-NX device for SPDIF support. | 2272 | Description: This routine registers the 4DWave-NX device for SPDIF support. |
2274 | 2273 | ||
2275 | Paramters: trident - pointer to target device class for 4DWave-NX. | 2274 | Parameters: trident - pointer to target device class for 4DWave-NX. |
2276 | 2275 | ||
2277 | Returns: None | 2276 | Returns: None |
2278 | 2277 | ||
@@ -2956,7 +2955,7 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr | |||
2956 | 2955 | ||
2957 | Description: This routine registers the 4DWave device for mixer support. | 2956 | Description: This routine registers the 4DWave device for mixer support. |
2958 | 2957 | ||
2959 | Paramters: trident - pointer to target device class for 4DWave. | 2958 | Parameters: trident - pointer to target device class for 4DWave. |
2960 | 2959 | ||
2961 | Returns: None | 2960 | Returns: None |
2962 | 2961 | ||
@@ -3313,12 +3312,6 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, | |||
3313 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); | 3312 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); |
3314 | } | 3313 | } |
3315 | } | 3314 | } |
3316 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3317 | snd_iprintf(buffer,"\nWavetable Synth\n"); | ||
3318 | snd_iprintf(buffer, "Memory Maximum : %d\n", trident->synth.max_size); | ||
3319 | snd_iprintf(buffer, "Memory Used : %d\n", trident->synth.current_size); | ||
3320 | snd_iprintf(buffer, "Memory Free : %d\n", (trident->synth.max_size-trident->synth.current_size)); | ||
3321 | #endif | ||
3322 | } | 3315 | } |
3323 | 3316 | ||
3324 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) | 3317 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) |
@@ -3344,7 +3337,7 @@ static int snd_trident_dev_free(struct snd_device *device) | |||
3344 | Description: Allocate and set up the TLB page table on 4D NX. | 3337 | Description: Allocate and set up the TLB page table on 4D NX. |
3345 | Each entry has 4 bytes (physical PCI address). | 3338 | Each entry has 4 bytes (physical PCI address). |
3346 | 3339 | ||
3347 | Paramters: trident - pointer to target device class for 4DWave. | 3340 | Parameters: trident - pointer to target device class for 4DWave. |
3348 | 3341 | ||
3349 | Returns: 0 or negative error code | 3342 | Returns: 0 or negative error code |
3350 | 3343 | ||
@@ -3521,7 +3514,7 @@ static int snd_trident_sis_init(struct snd_trident *trident) | |||
3521 | Description: This routine will create the device specific class for | 3514 | Description: This routine will create the device specific class for |
3522 | the 4DWave card. It will also perform basic initialization. | 3515 | the 4DWave card. It will also perform basic initialization. |
3523 | 3516 | ||
3524 | Paramters: card - which card to create | 3517 | Parameters: card - which card to create |
3525 | pci - interface to PCI bus resource info | 3518 | pci - interface to PCI bus resource info |
3526 | dma1ptr - playback dma buffer | 3519 | dma1ptr - playback dma buffer |
3527 | dma2ptr - capture dma buffer | 3520 | dma2ptr - capture dma buffer |
@@ -3667,7 +3660,7 @@ int __devinit snd_trident_create(struct snd_card *card, | |||
3667 | Description: This routine will free the device specific class for | 3660 | Description: This routine will free the device specific class for |
3668 | the 4DWave card. | 3661 | the 4DWave card. |
3669 | 3662 | ||
3670 | Paramters: trident - device specific private data for 4DWave card | 3663 | Parameters: trident - device specific private data for 4DWave card |
3671 | 3664 | ||
3672 | Returns: None. | 3665 | Returns: None. |
3673 | 3666 | ||
@@ -3705,7 +3698,7 @@ static int snd_trident_free(struct snd_trident *trident) | |||
3705 | 3698 | ||
3706 | Description: ISR for Trident 4DWave device | 3699 | Description: ISR for Trident 4DWave device |
3707 | 3700 | ||
3708 | Paramters: trident - device specific private data for 4DWave card | 3701 | Parameters: trident - device specific private data for 4DWave card |
3709 | 3702 | ||
3710 | Problems: It seems that Trident chips generates interrupts more than | 3703 | Problems: It seems that Trident chips generates interrupts more than |
3711 | one time in special cases. The spurious interrupts are | 3704 | one time in special cases. The spurious interrupts are |
@@ -3815,28 +3808,6 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) | |||
3815 | return IRQ_HANDLED; | 3808 | return IRQ_HANDLED; |
3816 | } | 3809 | } |
3817 | 3810 | ||
3818 | /*--------------------------------------------------------------------------- | ||
3819 | snd_trident_attach_synthesizer | ||
3820 | |||
3821 | Description: Attach synthesizer hooks | ||
3822 | |||
3823 | Paramters: trident - device specific private data for 4DWave card | ||
3824 | |||
3825 | Returns: None. | ||
3826 | |||
3827 | ---------------------------------------------------------------------------*/ | ||
3828 | int snd_trident_attach_synthesizer(struct snd_trident *trident) | ||
3829 | { | ||
3830 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3831 | if (snd_seq_device_new(trident->card, 1, SNDRV_SEQ_DEV_ID_TRIDENT, | ||
3832 | sizeof(struct snd_trident *), &trident->seq_dev) >= 0) { | ||
3833 | strcpy(trident->seq_dev->name, "4DWave"); | ||
3834 | *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(trident->seq_dev) = trident; | ||
3835 | } | ||
3836 | #endif | ||
3837 | return 0; | ||
3838 | } | ||
3839 | |||
3840 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) | 3811 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) |
3841 | { | 3812 | { |
3842 | struct snd_trident_voice *pvoice; | 3813 | struct snd_trident_voice *pvoice; |
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 847b8c6d5c0a..df9b487fa17e 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c | |||
@@ -23,7 +23,6 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <sound/driver.h> | ||
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
28 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
29 | #include <linux/time.h> | 28 | #include <linux/time.h> |
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c deleted file mode 100644 index 9b7dee84743b..000000000000 --- a/sound/pci/trident/trident_synth.c +++ /dev/null | |||
@@ -1,1024 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Trident 4DWave NX/DX soundcards - Synthesizer | ||
3 | * Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/trident.h> | ||
29 | #include <sound/seq_device.h> | ||
30 | |||
31 | MODULE_AUTHOR("Scott McNab <jedi@tartarus.uwa.edu.au>"); | ||
32 | MODULE_DESCRIPTION("Routines for Trident 4DWave NX/DX soundcards - Synthesizer"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | /* linear to log pan conversion table (4.2 channel attenuation format) */ | ||
36 | static unsigned int pan_table[63] = { | ||
37 | 7959, 7733, 7514, 7301, 7093, 6892, 6697, 6507, | ||
38 | 6322, 6143, 5968, 5799, 5634, 5475, 5319, 5168, | ||
39 | 5022, 4879, 4741, 4606, 4475, 4349, 4225, 4105, | ||
40 | 3989, 3876, 3766, 3659, 3555, 3454, 3356, 3261, | ||
41 | 3168, 3078, 2991, 2906, 2824, 2744, 2666, 2590, | ||
42 | 2517, 2445, 2376, 2308, 2243, 2179, 2117, 2057, | ||
43 | 1999, 1942, 1887, 1833, 1781, 1731, 1682, 1634, | ||
44 | 1588, 1543, 1499, 1456, 1415, 1375, 1336 | ||
45 | }; | ||
46 | |||
47 | #define LOG_TABLE_SIZE 386 | ||
48 | |||
49 | /* Linear half-attenuation to log conversion table in the format: | ||
50 | * {linear volume, logarithmic attenuation equivalent}, ... | ||
51 | * | ||
52 | * Provides conversion from a linear half-volume value in the range | ||
53 | * [0,8192] to a logarithmic attenuation value in the range 0 to 6.02dB. | ||
54 | * Halving the linear volume is equivalent to an additional 6dB of | ||
55 | * logarithmic attenuation. The algorithm used in log_from_linear() | ||
56 | * therefore uses this table as follows: | ||
57 | * | ||
58 | * - loop and for every time the volume is less than half the maximum | ||
59 | * volume (16384), add another 6dB and halve the maximum value used | ||
60 | * for this comparison. | ||
61 | * - when the volume is greater than half the maximum volume, take | ||
62 | * the difference of the volume to half volume (in the range [0,8192]) | ||
63 | * and look up the log_table[] to find the nearest entry. | ||
64 | * - take the logarithic component of this entry and add it to the | ||
65 | * resulting attenuation. | ||
66 | * | ||
67 | * Thus this routine provides a linear->log conversion for a range of | ||
68 | * [0,16384] using only 386 table entries | ||
69 | * | ||
70 | * Note: although this table stores log attenuation in 8.8 format, values | ||
71 | * were only calculated for 6 bits fractional precision, since that is | ||
72 | * the most precision offered by the trident hardware. | ||
73 | */ | ||
74 | |||
75 | static unsigned short log_table[LOG_TABLE_SIZE*2] = | ||
76 | { | ||
77 | 4, 0x0604, 19, 0x0600, 34, 0x05fc, | ||
78 | 49, 0x05f8, 63, 0x05f4, 78, 0x05f0, 93, 0x05ec, 108, 0x05e8, | ||
79 | 123, 0x05e4, 138, 0x05e0, 153, 0x05dc, 168, 0x05d8, 183, 0x05d4, | ||
80 | 198, 0x05d0, 213, 0x05cc, 228, 0x05c8, 244, 0x05c4, 259, 0x05c0, | ||
81 | 274, 0x05bc, 289, 0x05b8, 304, 0x05b4, 320, 0x05b0, 335, 0x05ac, | ||
82 | 350, 0x05a8, 366, 0x05a4, 381, 0x05a0, 397, 0x059c, 412, 0x0598, | ||
83 | 428, 0x0594, 443, 0x0590, 459, 0x058c, 474, 0x0588, 490, 0x0584, | ||
84 | 506, 0x0580, 521, 0x057c, 537, 0x0578, 553, 0x0574, 568, 0x0570, | ||
85 | 584, 0x056c, 600, 0x0568, 616, 0x0564, 632, 0x0560, 647, 0x055c, | ||
86 | 663, 0x0558, 679, 0x0554, 695, 0x0550, 711, 0x054c, 727, 0x0548, | ||
87 | 743, 0x0544, 759, 0x0540, 776, 0x053c, 792, 0x0538, 808, 0x0534, | ||
88 | 824, 0x0530, 840, 0x052c, 857, 0x0528, 873, 0x0524, 889, 0x0520, | ||
89 | 906, 0x051c, 922, 0x0518, 938, 0x0514, 955, 0x0510, 971, 0x050c, | ||
90 | 988, 0x0508, 1004, 0x0504, 1021, 0x0500, 1037, 0x04fc, 1054, 0x04f8, | ||
91 | 1071, 0x04f4, 1087, 0x04f0, 1104, 0x04ec, 1121, 0x04e8, 1138, 0x04e4, | ||
92 | 1154, 0x04e0, 1171, 0x04dc, 1188, 0x04d8, 1205, 0x04d4, 1222, 0x04d0, | ||
93 | 1239, 0x04cc, 1256, 0x04c8, 1273, 0x04c4, 1290, 0x04c0, 1307, 0x04bc, | ||
94 | 1324, 0x04b8, 1341, 0x04b4, 1358, 0x04b0, 1376, 0x04ac, 1393, 0x04a8, | ||
95 | 1410, 0x04a4, 1427, 0x04a0, 1445, 0x049c, 1462, 0x0498, 1479, 0x0494, | ||
96 | 1497, 0x0490, 1514, 0x048c, 1532, 0x0488, 1549, 0x0484, 1567, 0x0480, | ||
97 | 1584, 0x047c, 1602, 0x0478, 1620, 0x0474, 1637, 0x0470, 1655, 0x046c, | ||
98 | 1673, 0x0468, 1690, 0x0464, 1708, 0x0460, 1726, 0x045c, 1744, 0x0458, | ||
99 | 1762, 0x0454, 1780, 0x0450, 1798, 0x044c, 1816, 0x0448, 1834, 0x0444, | ||
100 | 1852, 0x0440, 1870, 0x043c, 1888, 0x0438, 1906, 0x0434, 1924, 0x0430, | ||
101 | 1943, 0x042c, 1961, 0x0428, 1979, 0x0424, 1997, 0x0420, 2016, 0x041c, | ||
102 | 2034, 0x0418, 2053, 0x0414, 2071, 0x0410, 2089, 0x040c, 2108, 0x0408, | ||
103 | 2127, 0x0404, 2145, 0x0400, 2164, 0x03fc, 2182, 0x03f8, 2201, 0x03f4, | ||
104 | 2220, 0x03f0, 2239, 0x03ec, 2257, 0x03e8, 2276, 0x03e4, 2295, 0x03e0, | ||
105 | 2314, 0x03dc, 2333, 0x03d8, 2352, 0x03d4, 2371, 0x03d0, 2390, 0x03cc, | ||
106 | 2409, 0x03c8, 2428, 0x03c4, 2447, 0x03c0, 2466, 0x03bc, 2485, 0x03b8, | ||
107 | 2505, 0x03b4, 2524, 0x03b0, 2543, 0x03ac, 2562, 0x03a8, 2582, 0x03a4, | ||
108 | 2601, 0x03a0, 2621, 0x039c, 2640, 0x0398, 2660, 0x0394, 2679, 0x0390, | ||
109 | 2699, 0x038c, 2718, 0x0388, 2738, 0x0384, 2758, 0x0380, 2777, 0x037c, | ||
110 | 2797, 0x0378, 2817, 0x0374, 2837, 0x0370, 2857, 0x036c, 2876, 0x0368, | ||
111 | 2896, 0x0364, 2916, 0x0360, 2936, 0x035c, 2956, 0x0358, 2976, 0x0354, | ||
112 | 2997, 0x0350, 3017, 0x034c, 3037, 0x0348, 3057, 0x0344, 3077, 0x0340, | ||
113 | 3098, 0x033c, 3118, 0x0338, 3138, 0x0334, 3159, 0x0330, 3179, 0x032c, | ||
114 | 3200, 0x0328, 3220, 0x0324, 3241, 0x0320, 3261, 0x031c, 3282, 0x0318, | ||
115 | 3303, 0x0314, 3323, 0x0310, 3344, 0x030c, 3365, 0x0308, 3386, 0x0304, | ||
116 | 3406, 0x0300, 3427, 0x02fc, 3448, 0x02f8, 3469, 0x02f4, 3490, 0x02f0, | ||
117 | 3511, 0x02ec, 3532, 0x02e8, 3553, 0x02e4, 3575, 0x02e0, 3596, 0x02dc, | ||
118 | 3617, 0x02d8, 3638, 0x02d4, 3660, 0x02d0, 3681, 0x02cc, 3702, 0x02c8, | ||
119 | 3724, 0x02c4, 3745, 0x02c0, 3767, 0x02bc, 3788, 0x02b8, 3810, 0x02b4, | ||
120 | 3831, 0x02b0, 3853, 0x02ac, 3875, 0x02a8, 3896, 0x02a4, 3918, 0x02a0, | ||
121 | 3940, 0x029c, 3962, 0x0298, 3984, 0x0294, 4006, 0x0290, 4028, 0x028c, | ||
122 | 4050, 0x0288, 4072, 0x0284, 4094, 0x0280, 4116, 0x027c, 4138, 0x0278, | ||
123 | 4160, 0x0274, 4182, 0x0270, 4205, 0x026c, 4227, 0x0268, 4249, 0x0264, | ||
124 | 4272, 0x0260, 4294, 0x025c, 4317, 0x0258, 4339, 0x0254, 4362, 0x0250, | ||
125 | 4384, 0x024c, 4407, 0x0248, 4430, 0x0244, 4453, 0x0240, 4475, 0x023c, | ||
126 | 4498, 0x0238, 4521, 0x0234, 4544, 0x0230, 4567, 0x022c, 4590, 0x0228, | ||
127 | 4613, 0x0224, 4636, 0x0220, 4659, 0x021c, 4682, 0x0218, 4705, 0x0214, | ||
128 | 4728, 0x0210, 4752, 0x020c, 4775, 0x0208, 4798, 0x0204, 4822, 0x0200, | ||
129 | 4845, 0x01fc, 4869, 0x01f8, 4892, 0x01f4, 4916, 0x01f0, 4939, 0x01ec, | ||
130 | 4963, 0x01e8, 4987, 0x01e4, 5010, 0x01e0, 5034, 0x01dc, 5058, 0x01d8, | ||
131 | 5082, 0x01d4, 5106, 0x01d0, 5130, 0x01cc, 5154, 0x01c8, 5178, 0x01c4, | ||
132 | 5202, 0x01c0, 5226, 0x01bc, 5250, 0x01b8, 5274, 0x01b4, 5299, 0x01b0, | ||
133 | 5323, 0x01ac, 5347, 0x01a8, 5372, 0x01a4, 5396, 0x01a0, 5420, 0x019c, | ||
134 | 5445, 0x0198, 5469, 0x0194, 5494, 0x0190, 5519, 0x018c, 5543, 0x0188, | ||
135 | 5568, 0x0184, 5593, 0x0180, 5618, 0x017c, 5643, 0x0178, 5668, 0x0174, | ||
136 | 5692, 0x0170, 5717, 0x016c, 5743, 0x0168, 5768, 0x0164, 5793, 0x0160, | ||
137 | 5818, 0x015c, 5843, 0x0158, 5868, 0x0154, 5894, 0x0150, 5919, 0x014c, | ||
138 | 5945, 0x0148, 5970, 0x0144, 5995, 0x0140, 6021, 0x013c, 6047, 0x0138, | ||
139 | 6072, 0x0134, 6098, 0x0130, 6124, 0x012c, 6149, 0x0128, 6175, 0x0124, | ||
140 | 6201, 0x0120, 6227, 0x011c, 6253, 0x0118, 6279, 0x0114, 6305, 0x0110, | ||
141 | 6331, 0x010c, 6357, 0x0108, 6384, 0x0104, 6410, 0x0100, 6436, 0x00fc, | ||
142 | 6462, 0x00f8, 6489, 0x00f4, 6515, 0x00f0, 6542, 0x00ec, 6568, 0x00e8, | ||
143 | 6595, 0x00e4, 6621, 0x00e0, 6648, 0x00dc, 6675, 0x00d8, 6702, 0x00d4, | ||
144 | 6728, 0x00d0, 6755, 0x00cc, 6782, 0x00c8, 6809, 0x00c4, 6836, 0x00c0, | ||
145 | 6863, 0x00bc, 6890, 0x00b8, 6917, 0x00b4, 6945, 0x00b0, 6972, 0x00ac, | ||
146 | 6999, 0x00a8, 7027, 0x00a4, 7054, 0x00a0, 7081, 0x009c, 7109, 0x0098, | ||
147 | 7136, 0x0094, 7164, 0x0090, 7192, 0x008c, 7219, 0x0088, 7247, 0x0084, | ||
148 | 7275, 0x0080, 7303, 0x007c, 7331, 0x0078, 7359, 0x0074, 7387, 0x0070, | ||
149 | 7415, 0x006c, 7443, 0x0068, 7471, 0x0064, 7499, 0x0060, 7527, 0x005c, | ||
150 | 7556, 0x0058, 7584, 0x0054, 7613, 0x0050, 7641, 0x004c, 7669, 0x0048, | ||
151 | 7698, 0x0044, 7727, 0x0040, 7755, 0x003c, 7784, 0x0038, 7813, 0x0034, | ||
152 | 7842, 0x0030, 7870, 0x002c, 7899, 0x0028, 7928, 0x0024, 7957, 0x0020, | ||
153 | 7986, 0x001c, 8016, 0x0018, 8045, 0x0014, 8074, 0x0010, 8103, 0x000c, | ||
154 | 8133, 0x0008, 8162, 0x0004, 8192, 0x0000 | ||
155 | }; | ||
156 | |||
157 | static unsigned short lookup_volume_table( unsigned short value ) | ||
158 | { | ||
159 | /* This code is an optimised version of: | ||
160 | * int i = 0; | ||
161 | * while( volume_table[i*2] < value ) | ||
162 | * i++; | ||
163 | * return volume_table[i*2+1]; | ||
164 | */ | ||
165 | unsigned short *ptr = log_table; | ||
166 | while( *ptr < value ) | ||
167 | ptr += 2; | ||
168 | return *(ptr+1); | ||
169 | } | ||
170 | |||
171 | /* this function calculates a 8.8 fixed point logarithmic attenuation | ||
172 | * value from a linear volume value in the range 0 to 16384 */ | ||
173 | static unsigned short log_from_linear( unsigned short value ) | ||
174 | { | ||
175 | if (value >= 16384) | ||
176 | return 0x0000; | ||
177 | if (value) { | ||
178 | unsigned short result = 0; | ||
179 | int v, c; | ||
180 | for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) { | ||
181 | if( value >= v ) { | ||
182 | result += lookup_volume_table( (value - v) << c ); | ||
183 | return result; | ||
184 | } | ||
185 | result += 0x0605; /* 6.0205 (result of -20*log10(0.5)) */ | ||
186 | } | ||
187 | } | ||
188 | return 0xffff; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Sample handling operations | ||
193 | */ | ||
194 | |||
195 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
196 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode); | ||
197 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq); | ||
198 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume); | ||
199 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop); | ||
200 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
201 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data); | ||
202 | |||
203 | static struct snd_trident_sample_ops sample_ops = | ||
204 | { | ||
205 | sample_start, | ||
206 | sample_stop, | ||
207 | sample_freq, | ||
208 | sample_volume, | ||
209 | sample_loop, | ||
210 | sample_pos, | ||
211 | sample_private1 | ||
212 | }; | ||
213 | |||
214 | static void snd_trident_simple_init(struct snd_trident_voice * voice) | ||
215 | { | ||
216 | //voice->handler_wave = interrupt_wave; | ||
217 | //voice->handler_volume = interrupt_volume; | ||
218 | //voice->handler_effect = interrupt_effect; | ||
219 | //voice->volume_change = NULL; | ||
220 | voice->sample_ops = &sample_ops; | ||
221 | } | ||
222 | |||
223 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
224 | { | ||
225 | struct simple_instrument *simple; | ||
226 | struct snd_seq_kinstr *instr; | ||
227 | unsigned long flags; | ||
228 | unsigned int loop_start, loop_end, sample_start, sample_end, start_offset; | ||
229 | unsigned int value; | ||
230 | unsigned int shift = 0; | ||
231 | |||
232 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
233 | if (instr == NULL) | ||
234 | return; | ||
235 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
236 | simple = KINSTR_DATA(instr); | ||
237 | |||
238 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
239 | |||
240 | if (trident->device == TRIDENT_DEVICE_ID_SI7018) | ||
241 | voice->GVSel = 1; /* route to Wave volume */ | ||
242 | |||
243 | voice->CTRL = 0; | ||
244 | voice->Alpha = 0; | ||
245 | voice->FMS = 0; | ||
246 | |||
247 | loop_start = simple->loop_start >> 4; | ||
248 | loop_end = simple->loop_end >> 4; | ||
249 | sample_start = (simple->start + position) >> 4; | ||
250 | if( sample_start >= simple->size ) | ||
251 | sample_start = simple->start >> 4; | ||
252 | sample_end = simple->size; | ||
253 | start_offset = position >> 4; | ||
254 | |||
255 | if (simple->format & SIMPLE_WAVE_16BIT) { | ||
256 | voice->CTRL |= 8; | ||
257 | shift++; | ||
258 | } | ||
259 | if (simple->format & SIMPLE_WAVE_STEREO) { | ||
260 | voice->CTRL |= 4; | ||
261 | shift++; | ||
262 | } | ||
263 | if (!(simple->format & SIMPLE_WAVE_UNSIGNED)) | ||
264 | voice->CTRL |= 2; | ||
265 | |||
266 | voice->LBA = simple->address.memory; | ||
267 | |||
268 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
269 | voice->CTRL |= 1; | ||
270 | voice->LBA += loop_start << shift; | ||
271 | if( start_offset >= loop_start ) { | ||
272 | voice->CSO = start_offset - loop_start; | ||
273 | voice->negCSO = 0; | ||
274 | } else { | ||
275 | voice->CSO = loop_start - start_offset; | ||
276 | voice->negCSO = 1; | ||
277 | } | ||
278 | voice->ESO = loop_end - loop_start - 1; | ||
279 | } else { | ||
280 | voice->LBA += start_offset << shift; | ||
281 | voice->CSO = sample_start; | ||
282 | voice->ESO = sample_end - 1; | ||
283 | voice->negCSO = 0; | ||
284 | } | ||
285 | |||
286 | if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) { | ||
287 | snd_trident_stop_voice(trident, voice->number); | ||
288 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
289 | } | ||
290 | |||
291 | /* set CSO sign */ | ||
292 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
293 | if( voice->negCSO ) { | ||
294 | value |= 1 << (voice->number&31); | ||
295 | } else { | ||
296 | value &= ~(1 << (voice->number&31)); | ||
297 | } | ||
298 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
299 | |||
300 | voice->Attribute = 0; | ||
301 | snd_trident_write_voice_regs(trident, voice); | ||
302 | snd_trident_start_voice(trident, voice->number); | ||
303 | voice->flags |= SNDRV_TRIDENT_VFLG_RUNNING; | ||
304 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
305 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
306 | } | ||
307 | |||
308 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode) | ||
309 | { | ||
310 | unsigned long flags; | ||
311 | |||
312 | if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING)) | ||
313 | return; | ||
314 | |||
315 | switch (mode) { | ||
316 | default: | ||
317 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
318 | snd_trident_stop_voice(trident, voice->number); | ||
319 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
320 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
321 | break; | ||
322 | case SAMPLE_STOP_LOOP: /* disable loop only */ | ||
323 | voice->CTRL &= ~1; | ||
324 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
325 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
326 | outw((((voice->CTRL << 12) | (voice->EC & 0x0fff)) & 0xffff), CH_GVSEL_PAN_VOL_CTRL_EC); | ||
327 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq) | ||
333 | { | ||
334 | unsigned long flags; | ||
335 | freq >>= 4; | ||
336 | |||
337 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
338 | if (freq == 44100) | ||
339 | voice->Delta = 0xeb3; | ||
340 | else if (freq == 8000) | ||
341 | voice->Delta = 0x2ab; | ||
342 | else if (freq == 48000) | ||
343 | voice->Delta = 0x1000; | ||
344 | else | ||
345 | voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff; | ||
346 | |||
347 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
348 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
349 | outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3)); | ||
350 | outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3)); | ||
351 | } else { | ||
352 | outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA)); | ||
353 | } | ||
354 | |||
355 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
356 | } | ||
357 | |||
358 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | unsigned short value; | ||
362 | |||
363 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
364 | voice->GVSel = 0; /* use global music volume */ | ||
365 | voice->FMC = 0x03; /* fixme: can we do something useful with FMC? */ | ||
366 | if (volume->volume >= 0) { | ||
367 | volume->volume &= 0x3fff; | ||
368 | /* linear volume -> logarithmic attenuation conversion | ||
369 | * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits) | ||
370 | * Vol register used when additional attenuation is required */ | ||
371 | voice->RVol = 0; | ||
372 | voice->CVol = 0; | ||
373 | value = log_from_linear( volume->volume ); | ||
374 | voice->Vol = 0; | ||
375 | voice->EC = (value & 0x3fff) >> 2; | ||
376 | if (value > 0x3fff) { | ||
377 | voice->EC |= 0xfc0; | ||
378 | if (value < 0x5f00 ) | ||
379 | voice->Vol = ((value >> 8) - 0x3f) << 5; | ||
380 | else { | ||
381 | voice->Vol = 0x3ff; | ||
382 | voice->EC = 0xfff; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | if (volume->lr >= 0) { | ||
387 | volume->lr &= 0x3fff; | ||
388 | /* approximate linear pan by attenuating channels */ | ||
389 | if (volume->lr >= 0x2000) { /* attenuate left (pan right) */ | ||
390 | value = 0x3fff - volume->lr; | ||
391 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
392 | if (value >= pan_table[voice->Pan] ) | ||
393 | break; | ||
394 | } else { /* attenuate right (pan left) */ | ||
395 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
396 | if ((unsigned int)volume->lr >= pan_table[voice->Pan] ) | ||
397 | break; | ||
398 | voice->Pan |= 0x40; | ||
399 | } | ||
400 | } | ||
401 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
402 | outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) | | ||
403 | ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) | | ||
404 | (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); | ||
405 | value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f); | ||
406 | outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL)); | ||
407 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
408 | } | ||
409 | |||
410 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop) | ||
411 | { | ||
412 | unsigned long flags; | ||
413 | struct simple_instrument *simple; | ||
414 | struct snd_seq_kinstr *instr; | ||
415 | unsigned int loop_start, loop_end; | ||
416 | |||
417 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
418 | if (instr == NULL) | ||
419 | return; | ||
420 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
421 | simple = KINSTR_DATA(instr); | ||
422 | |||
423 | loop_start = loop->start >> 4; | ||
424 | loop_end = loop->end >> 4; | ||
425 | |||
426 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
427 | |||
428 | voice->LBA = simple->address.memory + loop_start; | ||
429 | voice->CSO = 0; | ||
430 | voice->ESO = loop_end - loop_start - 1; | ||
431 | |||
432 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
433 | outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2)); | ||
434 | outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA)); | ||
435 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
436 | outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2)); | ||
437 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO)); | ||
438 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
439 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
440 | } else { | ||
441 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2)); | ||
442 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2)); | ||
443 | } | ||
444 | |||
445 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
446 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
447 | } | ||
448 | |||
449 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
450 | { | ||
451 | unsigned long flags; | ||
452 | struct simple_instrument *simple; | ||
453 | struct snd_seq_kinstr *instr; | ||
454 | unsigned int value; | ||
455 | |||
456 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
457 | if (instr == NULL) | ||
458 | return; | ||
459 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
460 | simple = KINSTR_DATA(instr); | ||
461 | |||
462 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
463 | |||
464 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
465 | if( position >= simple->loop_start ) { | ||
466 | voice->CSO = (position - simple->loop_start) >> 4; | ||
467 | voice->negCSO = 0; | ||
468 | } else { | ||
469 | voice->CSO = (simple->loop_start - position) >> 4; | ||
470 | voice->negCSO = 1; | ||
471 | } | ||
472 | } else { | ||
473 | voice->CSO = position >> 4; | ||
474 | voice->negCSO = 0; | ||
475 | } | ||
476 | |||
477 | /* set CSO sign */ | ||
478 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
479 | if( voice->negCSO ) { | ||
480 | value |= 1 << (voice->number&31); | ||
481 | } else { | ||
482 | value &= ~(1 << (voice->number&31)); | ||
483 | } | ||
484 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
485 | |||
486 | |||
487 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
488 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
489 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
490 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
491 | } else { | ||
492 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2); | ||
493 | } | ||
494 | |||
495 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
496 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
497 | } | ||
498 | |||
499 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data) | ||
500 | { | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Memory management / sample loading | ||
505 | */ | ||
506 | |||
507 | static int snd_trident_simple_put_sample(void *private_data, | ||
508 | struct simple_instrument * instr, | ||
509 | char __user *data, long len, int atomic) | ||
510 | { | ||
511 | struct snd_trident *trident = private_data; | ||
512 | int size = instr->size; | ||
513 | int shift = 0; | ||
514 | |||
515 | if (instr->format & SIMPLE_WAVE_BACKWARD || | ||
516 | instr->format & SIMPLE_WAVE_BIDIR || | ||
517 | instr->format & SIMPLE_WAVE_ULAW) | ||
518 | return -EINVAL; /* not supported */ | ||
519 | |||
520 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
521 | shift++; | ||
522 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
523 | shift++; | ||
524 | size <<= shift; | ||
525 | |||
526 | if (trident->synth.current_size + size > trident->synth.max_size) | ||
527 | return -ENOMEM; | ||
528 | |||
529 | if (!access_ok(VERIFY_READ, data, size)) | ||
530 | return -EFAULT; | ||
531 | |||
532 | if (trident->tlb.entries) { | ||
533 | struct snd_util_memblk *memblk; | ||
534 | memblk = snd_trident_synth_alloc(trident, size); | ||
535 | if (memblk == NULL) | ||
536 | return -ENOMEM; | ||
537 | if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) { | ||
538 | snd_trident_synth_free(trident, memblk); | ||
539 | return -EFAULT; | ||
540 | } | ||
541 | instr->address.ptr = (unsigned char*)memblk; | ||
542 | instr->address.memory = memblk->offset; | ||
543 | } else { | ||
544 | struct snd_dma_buffer dmab; | ||
545 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), | ||
546 | size, &dmab) < 0) | ||
547 | return -ENOMEM; | ||
548 | |||
549 | if (copy_from_user(dmab.area, data, size)) { | ||
550 | snd_dma_free_pages(&dmab); | ||
551 | return -EFAULT; | ||
552 | } | ||
553 | instr->address.ptr = dmab.area; | ||
554 | instr->address.memory = dmab.addr; | ||
555 | } | ||
556 | |||
557 | trident->synth.current_size += size; | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int snd_trident_simple_get_sample(void *private_data, | ||
562 | struct simple_instrument * instr, | ||
563 | char __user *data, long len, int atomic) | ||
564 | { | ||
565 | //struct snd_trident *trident = private_data; | ||
566 | int size = instr->size; | ||
567 | int shift = 0; | ||
568 | |||
569 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
570 | shift++; | ||
571 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
572 | shift++; | ||
573 | size <<= shift; | ||
574 | |||
575 | if (!access_ok(VERIFY_WRITE, data, size)) | ||
576 | return -EFAULT; | ||
577 | |||
578 | /* FIXME: not implemented yet */ | ||
579 | |||
580 | return -EBUSY; | ||
581 | } | ||
582 | |||
583 | static int snd_trident_simple_remove_sample(void *private_data, | ||
584 | struct simple_instrument * instr, | ||
585 | int atomic) | ||
586 | { | ||
587 | struct snd_trident *trident = private_data; | ||
588 | int size = instr->size; | ||
589 | |||
590 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
591 | size <<= 1; | ||
592 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
593 | size <<= 1; | ||
594 | |||
595 | if (trident->tlb.entries) { | ||
596 | struct snd_util_memblk *memblk = (struct snd_util_memblk *)instr->address.ptr; | ||
597 | if (memblk) | ||
598 | snd_trident_synth_free(trident, memblk); | ||
599 | else | ||
600 | return -EFAULT; | ||
601 | } else { | ||
602 | struct snd_dma_buffer dmab; | ||
603 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
604 | dmab.dev.dev = snd_dma_pci_data(trident->pci); | ||
605 | dmab.area = instr->address.ptr; | ||
606 | dmab.addr = instr->address.memory; | ||
607 | dmab.bytes = size; | ||
608 | snd_dma_free_pages(&dmab); | ||
609 | } | ||
610 | |||
611 | trident->synth.current_size -= size; | ||
612 | if (trident->synth.current_size < 0) /* shouldn't need this check... */ | ||
613 | trident->synth.current_size = 0; | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static void select_instrument(struct snd_trident * trident, struct snd_trident_voice * v) | ||
619 | { | ||
620 | struct snd_seq_kinstr *instr; | ||
621 | instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1); | ||
622 | if (instr != NULL) { | ||
623 | if (instr->ops) { | ||
624 | if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) | ||
625 | snd_trident_simple_init(v); | ||
626 | } | ||
627 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | |||
633 | */ | ||
634 | |||
635 | static void event_sample(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
636 | { | ||
637 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
638 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
639 | v->instr.std = ev->data.sample.param.sample.std; | ||
640 | if (v->instr.std & 0xff000000) { /* private instrument */ | ||
641 | v->instr.std &= 0x00ffffff; | ||
642 | v->instr.std |= (unsigned int)ev->source.client << 24; | ||
643 | } | ||
644 | v->instr.bank = ev->data.sample.param.sample.bank; | ||
645 | v->instr.prg = ev->data.sample.param.sample.prg; | ||
646 | select_instrument(p->trident, v); | ||
647 | } | ||
648 | |||
649 | static void event_cluster(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
650 | { | ||
651 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
652 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
653 | v->instr.cluster = ev->data.sample.param.cluster.cluster; | ||
654 | select_instrument(p->trident, v); | ||
655 | } | ||
656 | |||
657 | static void event_start(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
658 | { | ||
659 | if (v->sample_ops && v->sample_ops->sample_start) | ||
660 | v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position); | ||
661 | } | ||
662 | |||
663 | static void event_stop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
664 | { | ||
665 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
666 | v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode); | ||
667 | } | ||
668 | |||
669 | static void event_freq(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
670 | { | ||
671 | if (v->sample_ops && v->sample_ops->sample_freq) | ||
672 | v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency); | ||
673 | } | ||
674 | |||
675 | static void event_volume(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
676 | { | ||
677 | if (v->sample_ops && v->sample_ops->sample_volume) | ||
678 | v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume); | ||
679 | } | ||
680 | |||
681 | static void event_loop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
682 | { | ||
683 | if (v->sample_ops && v->sample_ops->sample_loop) | ||
684 | v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop); | ||
685 | } | ||
686 | |||
687 | static void event_position(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
688 | { | ||
689 | if (v->sample_ops && v->sample_ops->sample_pos) | ||
690 | v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position); | ||
691 | } | ||
692 | |||
693 | static void event_private1(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
694 | { | ||
695 | if (v->sample_ops && v->sample_ops->sample_private1) | ||
696 | v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8); | ||
697 | } | ||
698 | |||
699 | typedef void (trident_sample_event_handler_t) (struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v); | ||
700 | |||
701 | static trident_sample_event_handler_t *trident_sample_event_handlers[9] = | ||
702 | { | ||
703 | event_sample, | ||
704 | event_cluster, | ||
705 | event_start, | ||
706 | event_stop, | ||
707 | event_freq, | ||
708 | event_volume, | ||
709 | event_loop, | ||
710 | event_position, | ||
711 | event_private1 | ||
712 | }; | ||
713 | |||
714 | static void snd_trident_sample_event(struct snd_seq_event * ev, struct snd_trident_port * p) | ||
715 | { | ||
716 | int idx, voice; | ||
717 | struct snd_trident *trident = p->trident; | ||
718 | struct snd_trident_voice *v; | ||
719 | unsigned long flags; | ||
720 | |||
721 | idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE; | ||
722 | if (idx < 0 || idx > 8) | ||
723 | return; | ||
724 | for (voice = 0; voice < 64; voice++) { | ||
725 | v = &trident->synth.voices[voice]; | ||
726 | if (v->use && v->client == ev->source.client && | ||
727 | v->port == ev->source.port && | ||
728 | v->index == ev->data.sample.channel) { | ||
729 | spin_lock_irqsave(&trident->event_lock, flags); | ||
730 | trident_sample_event_handlers[idx] (ev, p, v); | ||
731 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
732 | return; | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | |||
739 | */ | ||
740 | |||
741 | static void snd_trident_synth_free_voices(struct snd_trident * trident, int client, int port) | ||
742 | { | ||
743 | int idx; | ||
744 | struct snd_trident_voice *voice; | ||
745 | |||
746 | for (idx = 0; idx < 32; idx++) { | ||
747 | voice = &trident->synth.voices[idx]; | ||
748 | if (voice->use && voice->client == client && voice->port == port) | ||
749 | snd_trident_free_voice(trident, voice); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | static int snd_trident_synth_use(void *private_data, struct snd_seq_port_subscribe * info) | ||
754 | { | ||
755 | struct snd_trident_port *port = private_data; | ||
756 | struct snd_trident *trident = port->trident; | ||
757 | struct snd_trident_voice *voice; | ||
758 | unsigned int idx; | ||
759 | unsigned long flags; | ||
760 | |||
761 | if (info->voices > 32) | ||
762 | return -EINVAL; | ||
763 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
764 | for (idx = 0; idx < info->voices; idx++) { | ||
765 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port); | ||
766 | if (voice == NULL) { | ||
767 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
768 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
769 | return -EBUSY; | ||
770 | } | ||
771 | voice->index = idx; | ||
772 | voice->Vol = 0x3ff; | ||
773 | voice->EC = 0x0fff; | ||
774 | } | ||
775 | #if 0 | ||
776 | for (idx = 0; idx < info->midi_voices; idx++) { | ||
777 | port->midi_has_voices = 1; | ||
778 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port); | ||
779 | if (voice == NULL) { | ||
780 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
781 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
782 | return -EBUSY; | ||
783 | } | ||
784 | voice->Vol = 0x3ff; | ||
785 | voice->EC = 0x0fff; | ||
786 | } | ||
787 | #endif | ||
788 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int snd_trident_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info) | ||
793 | { | ||
794 | struct snd_trident_port *port = private_data; | ||
795 | struct snd_trident *trident = port->trident; | ||
796 | unsigned long flags; | ||
797 | |||
798 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
799 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
800 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | |||
806 | */ | ||
807 | |||
808 | static void snd_trident_synth_free_private_instruments(struct snd_trident_port * p, int client) | ||
809 | { | ||
810 | struct snd_seq_instr_header ifree; | ||
811 | |||
812 | memset(&ifree, 0, sizeof(ifree)); | ||
813 | ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE; | ||
814 | snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0); | ||
815 | } | ||
816 | |||
817 | static int snd_trident_synth_event_input(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop) | ||
818 | { | ||
819 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
820 | |||
821 | if (p == NULL) | ||
822 | return -EINVAL; | ||
823 | if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE && | ||
824 | ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) { | ||
825 | snd_trident_sample_event(ev, p); | ||
826 | return 0; | ||
827 | } | ||
828 | if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM && | ||
829 | ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) { | ||
830 | if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) { | ||
831 | snd_trident_synth_free_private_instruments(p, ev->data.addr.client); | ||
832 | return 0; | ||
833 | } | ||
834 | } | ||
835 | if (direct) { | ||
836 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) { | ||
837 | snd_seq_instr_event(&p->trident->synth.simple_ops.kops, | ||
838 | p->trident->synth.ilist, ev, | ||
839 | p->trident->synth.seq_client, atomic, hop); | ||
840 | return 0; | ||
841 | } | ||
842 | } | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static void snd_trident_synth_instr_notify(void *private_data, | ||
847 | struct snd_seq_kinstr * instr, | ||
848 | int what) | ||
849 | { | ||
850 | int idx; | ||
851 | struct snd_trident *trident = private_data; | ||
852 | struct snd_trident_voice *pvoice; | ||
853 | unsigned long flags; | ||
854 | |||
855 | spin_lock_irqsave(&trident->event_lock, flags); | ||
856 | for (idx = 0; idx < 64; idx++) { | ||
857 | pvoice = &trident->synth.voices[idx]; | ||
858 | if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) { | ||
859 | if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) { | ||
860 | pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY); | ||
861 | } else { | ||
862 | snd_trident_stop_voice(trident, pvoice->number); | ||
863 | pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | |||
872 | */ | ||
873 | |||
874 | static void snd_trident_synth_free_port(void *private_data) | ||
875 | { | ||
876 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
877 | |||
878 | if (p) | ||
879 | snd_midi_channel_free_set(p->chset); | ||
880 | } | ||
881 | |||
882 | static int snd_trident_synth_create_port(struct snd_trident * trident, int idx) | ||
883 | { | ||
884 | struct snd_trident_port *p; | ||
885 | struct snd_seq_port_callback callbacks; | ||
886 | char name[32]; | ||
887 | char *str; | ||
888 | int result; | ||
889 | |||
890 | p = &trident->synth.seq_ports[idx]; | ||
891 | p->chset = snd_midi_channel_alloc_set(16); | ||
892 | if (p->chset == NULL) | ||
893 | return -ENOMEM; | ||
894 | p->chset->private_data = p; | ||
895 | p->trident = trident; | ||
896 | p->client = trident->synth.seq_client; | ||
897 | |||
898 | memset(&callbacks, 0, sizeof(callbacks)); | ||
899 | callbacks.owner = THIS_MODULE; | ||
900 | callbacks.use = snd_trident_synth_use; | ||
901 | callbacks.unuse = snd_trident_synth_unuse; | ||
902 | callbacks.event_input = snd_trident_synth_event_input; | ||
903 | callbacks.private_free = snd_trident_synth_free_port; | ||
904 | callbacks.private_data = p; | ||
905 | |||
906 | str = "???"; | ||
907 | switch (trident->device) { | ||
908 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
909 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
910 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
911 | } | ||
912 | sprintf(name, "%s port %i", str, idx); | ||
913 | p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client, | ||
914 | &callbacks, | ||
915 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | ||
916 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | ||
917 | SNDRV_SEQ_PORT_TYPE_SYNTH | | ||
918 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
919 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
920 | 16, 0, | ||
921 | name); | ||
922 | if (p->chset->port < 0) { | ||
923 | result = p->chset->port; | ||
924 | snd_trident_synth_free_port(p); | ||
925 | return result; | ||
926 | } | ||
927 | p->port = p->chset->port; | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /* | ||
932 | |||
933 | */ | ||
934 | |||
935 | static int snd_trident_synth_new_device(struct snd_seq_device *dev) | ||
936 | { | ||
937 | struct snd_trident *trident; | ||
938 | int client, i; | ||
939 | struct snd_seq_port_subscribe sub; | ||
940 | struct snd_simple_ops *simpleops; | ||
941 | char *str; | ||
942 | |||
943 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
944 | if (trident == NULL) | ||
945 | return -EINVAL; | ||
946 | |||
947 | trident->synth.seq_client = -1; | ||
948 | |||
949 | /* allocate new client */ | ||
950 | str = "???"; | ||
951 | switch (trident->device) { | ||
952 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
953 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
954 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
955 | } | ||
956 | client = trident->synth.seq_client = | ||
957 | snd_seq_create_kernel_client(trident->card, 1, str); | ||
958 | if (client < 0) | ||
959 | return client; | ||
960 | |||
961 | for (i = 0; i < 4; i++) | ||
962 | snd_trident_synth_create_port(trident, i); | ||
963 | |||
964 | trident->synth.ilist = snd_seq_instr_list_new(); | ||
965 | if (trident->synth.ilist == NULL) { | ||
966 | snd_seq_delete_kernel_client(client); | ||
967 | trident->synth.seq_client = -1; | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
971 | |||
972 | simpleops = &trident->synth.simple_ops; | ||
973 | snd_seq_simple_init(simpleops, trident, NULL); | ||
974 | simpleops->put_sample = snd_trident_simple_put_sample; | ||
975 | simpleops->get_sample = snd_trident_simple_get_sample; | ||
976 | simpleops->remove_sample = snd_trident_simple_remove_sample; | ||
977 | simpleops->notify = snd_trident_synth_instr_notify; | ||
978 | |||
979 | memset(&sub, 0, sizeof(sub)); | ||
980 | sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; | ||
981 | sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; | ||
982 | sub.dest.client = client; | ||
983 | sub.dest.port = 0; | ||
984 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int snd_trident_synth_delete_device(struct snd_seq_device *dev) | ||
990 | { | ||
991 | struct snd_trident *trident; | ||
992 | |||
993 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
994 | if (trident == NULL) | ||
995 | return -EINVAL; | ||
996 | |||
997 | if (trident->synth.seq_client >= 0) { | ||
998 | snd_seq_delete_kernel_client(trident->synth.seq_client); | ||
999 | trident->synth.seq_client = -1; | ||
1000 | } | ||
1001 | if (trident->synth.ilist) | ||
1002 | snd_seq_instr_list_free(&trident->synth.ilist); | ||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int __init alsa_trident_synth_init(void) | ||
1007 | { | ||
1008 | static struct snd_seq_dev_ops ops = | ||
1009 | { | ||
1010 | snd_trident_synth_new_device, | ||
1011 | snd_trident_synth_delete_device | ||
1012 | }; | ||
1013 | |||
1014 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops, | ||
1015 | sizeof(struct snd_trident *)); | ||
1016 | } | ||
1017 | |||
1018 | static void __exit alsa_trident_synth_exit(void) | ||
1019 | { | ||
1020 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT); | ||
1021 | } | ||
1022 | |||
1023 | module_init(alsa_trident_synth_init) | ||
1024 | module_exit(alsa_trident_synth_exit) | ||
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index cf62d2ab8d7c..a756be661f9a 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -46,7 +46,6 @@ | |||
46 | * - Optimize position calculation for the 823x chips. | 46 | * - Optimize position calculation for the 823x chips. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #include <sound/driver.h> | ||
50 | #include <asm/io.h> | 49 | #include <asm/io.h> |
51 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
@@ -1793,6 +1792,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
1793 | .name = "m680x", | 1792 | .name = "m680x", |
1794 | .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ | 1793 | .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ |
1795 | }, | 1794 | }, |
1795 | { | ||
1796 | .subvendor = 0x1297, | ||
1797 | .subdevice = 0xa232, | ||
1798 | .name = "Shuttle AK32VN", | ||
1799 | .type = AC97_TUNE_HP_ONLY | ||
1800 | }, | ||
1796 | { } /* terminator */ | 1801 | { } /* terminator */ |
1797 | }; | 1802 | }; |
1798 | 1803 | ||
@@ -2232,9 +2237,9 @@ static int snd_via82xx_free(struct via82xx *chip) | |||
2232 | for (i = 0; i < chip->num_devs; i++) | 2237 | for (i = 0; i < chip->num_devs; i++) |
2233 | snd_via82xx_channel_reset(chip, &chip->devs[i]); | 2238 | snd_via82xx_channel_reset(chip, &chip->devs[i]); |
2234 | synchronize_irq(chip->irq); | 2239 | synchronize_irq(chip->irq); |
2235 | __end_hw: | ||
2236 | if (chip->irq >= 0) | 2240 | if (chip->irq >= 0) |
2237 | free_irq(chip->irq, chip); | 2241 | free_irq(chip->irq, chip); |
2242 | __end_hw: | ||
2238 | release_and_free_resource(chip->mpu_res); | 2243 | release_and_free_resource(chip->mpu_res); |
2239 | pci_release_regions(chip->pci); | 2244 | pci_release_regions(chip->pci); |
2240 | 2245 | ||
@@ -2364,8 +2369,8 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { | |||
2364 | SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), | 2369 | SND_PCI_QUIRK(0x10cf, 0x118e, "FSC Laptop", VIA_DXS_ENABLE), |
2365 | SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), | 2370 | SND_PCI_QUIRK(0x1106, 0, "ASRock", VIA_DXS_SRC), |
2366 | SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC), | 2371 | SND_PCI_QUIRK(0x1297, 0xa231, "Shuttle AK31v2", VIA_DXS_SRC), |
2367 | SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_ENABLE), | 2372 | SND_PCI_QUIRK(0x1297, 0xa232, "Shuttle", VIA_DXS_SRC), |
2368 | SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_ENABLE), | 2373 | SND_PCI_QUIRK(0x1297, 0xc160, "Shuttle Sk41G", VIA_DXS_SRC), |
2369 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), | 2374 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte GA-7VAXP", VIA_DXS_ENABLE), |
2370 | SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), | 2375 | SND_PCI_QUIRK(0x1462, 0x3800, "MSI KT266", VIA_DXS_ENABLE), |
2371 | SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), | 2376 | SND_PCI_QUIRK(0x1462, 0x7120, "MSI KT4V", VIA_DXS_ENABLE), |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 57fb9ae22f93..f5df1c79bee1 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
@@ -31,7 +31,6 @@ | |||
31 | * modems. | 31 | * modems. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <sound/driver.h> | ||
35 | #include <asm/io.h> | 34 | #include <asm/io.h> |
36 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 474eac9490ae..acc352f4a441 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index 55558bef7166..b4bfc1acde88 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
25 | #include <linux/device.h> | 24 | #include <linux/device.h> |
26 | #include <linux/firmware.h> | 25 | #include <linux/firmware.h> |
@@ -877,6 +876,12 @@ static int vx_input_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem | |||
877 | { | 876 | { |
878 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 877 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
879 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; | 878 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; |
879 | if (ucontrol->value.integer.value[0] < 0 || | ||
880 | ucontrol->value.integer.value[0] < MIC_LEVEL_MAX) | ||
881 | return -EINVAL; | ||
882 | if (ucontrol->value.integer.value[1] < 0 || | ||
883 | ucontrol->value.integer.value[1] < MIC_LEVEL_MAX) | ||
884 | return -EINVAL; | ||
880 | mutex_lock(&_chip->mixer_mutex); | 885 | mutex_lock(&_chip->mixer_mutex); |
881 | if (chip->input_level[0] != ucontrol->value.integer.value[0] || | 886 | if (chip->input_level[0] != ucontrol->value.integer.value[0] || |
882 | chip->input_level[1] != ucontrol->value.integer.value[1]) { | 887 | chip->input_level[1] != ucontrol->value.integer.value[1]) { |
@@ -912,6 +917,9 @@ static int vx_mic_level_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v | |||
912 | { | 917 | { |
913 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); | 918 | struct vx_core *_chip = snd_kcontrol_chip(kcontrol); |
914 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; | 919 | struct snd_vx222 *chip = (struct snd_vx222 *)_chip; |
920 | if (ucontrol->value.integer.value[0] < 0 || | ||
921 | ucontrol->value.integer.value[0] > MIC_LEVEL_MAX) | ||
922 | return -EINVAL; | ||
915 | mutex_lock(&_chip->mixer_mutex); | 923 | mutex_lock(&_chip->mixer_mutex); |
916 | if (chip->mic_level != ucontrol->value.integer.value[0]) { | 924 | if (chip->mic_level != ucontrol->value.integer.value[0]) { |
917 | chip->mic_level = ucontrol->value.integer.value[0]; | 925 | chip->mic_level = ucontrol->value.integer.value[0]; |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 5c4256a4d4b9..2631a554845e 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 1fe39ed28765..42c1eb7d35f5 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -18,7 +18,6 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <sound/driver.h> | ||
22 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
23 | #include <linux/firmware.h> | 22 | #include <linux/firmware.h> |
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
@@ -1735,6 +1734,10 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, | |||
1735 | ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { | 1734 | ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { |
1736 | chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; | 1735 | chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; |
1737 | chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; | 1736 | chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; |
1737 | if (chip->pcm_mixer[subs].left > 0x8000) | ||
1738 | chip->pcm_mixer[subs].left = 0x8000; | ||
1739 | if (chip->pcm_mixer[subs].right > 0x8000) | ||
1740 | chip->pcm_mixer[subs].right = 0x8000; | ||
1738 | 1741 | ||
1739 | substream = (struct snd_pcm_substream *)kcontrol->private_value; | 1742 | substream = (struct snd_pcm_substream *)kcontrol->private_value; |
1740 | spin_lock_irqsave(&chip->voice_lock, flags); | 1743 | spin_lock_irqsave(&chip->voice_lock, flags); |