blob: dfba00230d4dac5aab2613c0f5ed0cb0add79ce6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Creative Labs, Inc.
4 * Routines for effect processor FX8010
5 *
6 * BUGS:
7 * --
8 *
9 * TODO:
10 * --
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
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#include <sound/driver.h>
29#include <linux/pci.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080030#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/delay.h>
32#include <linux/slab.h>
Andreas Schwabbd01e7b2005-12-05 15:12:20 +010033#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/init.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010035#include <linux/mutex.h>
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <sound/core.h>
38#include <sound/emu10k1.h>
39
40#if 0 /* for testing purposes - digital out -> capture */
41#define EMU10K1_CAPTURE_DIGITAL_OUT
42#endif
43#if 0 /* for testing purposes - set S/PDIF to AC3 output */
44#define EMU10K1_SET_AC3_IEC958
45#endif
46#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
47#define EMU10K1_CENTER_LFE_FROM_FRONT
48#endif
49
50/*
51 * Tables
52 */
53
54static char *fxbuses[16] = {
55 /* 0x00 */ "PCM Left",
56 /* 0x01 */ "PCM Right",
57 /* 0x02 */ "PCM Surround Left",
58 /* 0x03 */ "PCM Surround Right",
59 /* 0x04 */ "MIDI Left",
60 /* 0x05 */ "MIDI Right",
61 /* 0x06 */ "Center",
62 /* 0x07 */ "LFE",
63 /* 0x08 */ NULL,
64 /* 0x09 */ NULL,
65 /* 0x0a */ NULL,
66 /* 0x0b */ NULL,
67 /* 0x0c */ "MIDI Reverb",
68 /* 0x0d */ "MIDI Chorus",
69 /* 0x0e */ NULL,
70 /* 0x0f */ NULL
71};
72
73static char *creative_ins[16] = {
74 /* 0x00 */ "AC97 Left",
75 /* 0x01 */ "AC97 Right",
76 /* 0x02 */ "TTL IEC958 Left",
77 /* 0x03 */ "TTL IEC958 Right",
78 /* 0x04 */ "Zoom Video Left",
79 /* 0x05 */ "Zoom Video Right",
80 /* 0x06 */ "Optical IEC958 Left",
81 /* 0x07 */ "Optical IEC958 Right",
82 /* 0x08 */ "Line/Mic 1 Left",
83 /* 0x09 */ "Line/Mic 1 Right",
84 /* 0x0a */ "Coaxial IEC958 Left",
85 /* 0x0b */ "Coaxial IEC958 Right",
86 /* 0x0c */ "Line/Mic 2 Left",
87 /* 0x0d */ "Line/Mic 2 Right",
88 /* 0x0e */ NULL,
89 /* 0x0f */ NULL
90};
91
92static char *audigy_ins[16] = {
93 /* 0x00 */ "AC97 Left",
94 /* 0x01 */ "AC97 Right",
95 /* 0x02 */ "Audigy CD Left",
96 /* 0x03 */ "Audigy CD Right",
97 /* 0x04 */ "Optical IEC958 Left",
98 /* 0x05 */ "Optical IEC958 Right",
99 /* 0x06 */ NULL,
100 /* 0x07 */ NULL,
101 /* 0x08 */ "Line/Mic 2 Left",
102 /* 0x09 */ "Line/Mic 2 Right",
103 /* 0x0a */ "SPDIF Left",
104 /* 0x0b */ "SPDIF Right",
105 /* 0x0c */ "Aux2 Left",
106 /* 0x0d */ "Aux2 Right",
107 /* 0x0e */ NULL,
108 /* 0x0f */ NULL
109};
110
111static char *creative_outs[32] = {
112 /* 0x00 */ "AC97 Left",
113 /* 0x01 */ "AC97 Right",
114 /* 0x02 */ "Optical IEC958 Left",
115 /* 0x03 */ "Optical IEC958 Right",
116 /* 0x04 */ "Center",
117 /* 0x05 */ "LFE",
118 /* 0x06 */ "Headphone Left",
119 /* 0x07 */ "Headphone Right",
120 /* 0x08 */ "Surround Left",
121 /* 0x09 */ "Surround Right",
122 /* 0x0a */ "PCM Capture Left",
123 /* 0x0b */ "PCM Capture Right",
124 /* 0x0c */ "MIC Capture",
125 /* 0x0d */ "AC97 Surround Left",
126 /* 0x0e */ "AC97 Surround Right",
127 /* 0x0f */ NULL,
128 /* 0x10 */ NULL,
129 /* 0x11 */ "Analog Center",
130 /* 0x12 */ "Analog LFE",
131 /* 0x13 */ NULL,
132 /* 0x14 */ NULL,
133 /* 0x15 */ NULL,
134 /* 0x16 */ NULL,
135 /* 0x17 */ NULL,
136 /* 0x18 */ NULL,
137 /* 0x19 */ NULL,
138 /* 0x1a */ NULL,
139 /* 0x1b */ NULL,
140 /* 0x1c */ NULL,
141 /* 0x1d */ NULL,
142 /* 0x1e */ NULL,
143 /* 0x1f */ NULL,
144};
145
146static char *audigy_outs[32] = {
147 /* 0x00 */ "Digital Front Left",
148 /* 0x01 */ "Digital Front Right",
149 /* 0x02 */ "Digital Center",
150 /* 0x03 */ "Digital LEF",
151 /* 0x04 */ "Headphone Left",
152 /* 0x05 */ "Headphone Right",
153 /* 0x06 */ "Digital Rear Left",
154 /* 0x07 */ "Digital Rear Right",
155 /* 0x08 */ "Front Left",
156 /* 0x09 */ "Front Right",
157 /* 0x0a */ "Center",
158 /* 0x0b */ "LFE",
159 /* 0x0c */ NULL,
160 /* 0x0d */ NULL,
161 /* 0x0e */ "Rear Left",
162 /* 0x0f */ "Rear Right",
163 /* 0x10 */ "AC97 Front Left",
164 /* 0x11 */ "AC97 Front Right",
165 /* 0x12 */ "ADC Caputre Left",
166 /* 0x13 */ "ADC Capture Right",
167 /* 0x14 */ NULL,
168 /* 0x15 */ NULL,
169 /* 0x16 */ NULL,
170 /* 0x17 */ NULL,
171 /* 0x18 */ NULL,
172 /* 0x19 */ NULL,
173 /* 0x1a */ NULL,
174 /* 0x1b */ NULL,
175 /* 0x1c */ NULL,
176 /* 0x1d */ NULL,
177 /* 0x1e */ NULL,
178 /* 0x1f */ NULL,
179};
180
181static const u32 bass_table[41][5] = {
182 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
183 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
184 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
185 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
186 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
187 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
188 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
189 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
190 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
191 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
192 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
193 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
194 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
195 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
196 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
197 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
198 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
199 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
200 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
201 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
202 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
203 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
204 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
205 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
206 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
207 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
208 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
209 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
210 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
211 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
212 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
213 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
214 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
215 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
216 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
217 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
218 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
219 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
220 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
221 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
222 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
223};
224
225static const u32 treble_table[41][5] = {
226 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
227 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
228 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
229 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
230 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
231 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
232 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
233 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
234 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
235 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
236 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
237 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
238 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
239 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
240 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
241 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
242 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
243 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
244 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
245 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
246 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
247 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
248 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
249 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
250 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
251 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
252 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
253 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
254 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
255 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
256 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
257 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
258 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
259 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
260 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
261 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
262 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
263 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
264 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
265 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
266 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
267};
268
269static const u32 db_table[101] = {
270 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
271 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
272 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
273 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
274 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
275 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
276 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
277 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
278 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
279 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
280 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
281 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
282 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
283 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
284 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
285 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
286 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
287 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
288 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
289 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
290 0x7fffffff,
291};
292
293static const u32 onoff_table[2] = {
294 0x00000000, 0x00000001
295};
296
297/*
298 */
299
300static inline mm_segment_t snd_enter_user(void)
301{
302 mm_segment_t fs = get_fs();
303 set_fs(get_ds());
304 return fs;
305}
306
307static inline void snd_leave_user(mm_segment_t fs)
308{
309 set_fs(fs);
310}
311
312/*
313 * controls
314 */
315
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100316static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100318 struct snd_emu10k1_fx8010_ctl *ctl =
319 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 if (ctl->min == 0 && ctl->max == 1)
322 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
323 else
324 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
325 uinfo->count = ctl->vcount;
326 uinfo->value.integer.min = ctl->min;
327 uinfo->value.integer.max = ctl->max;
328 return 0;
329}
330
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100331static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100333 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
334 struct snd_emu10k1_fx8010_ctl *ctl =
335 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 unsigned long flags;
337 unsigned int i;
338
339 spin_lock_irqsave(&emu->reg_lock, flags);
340 for (i = 0; i < ctl->vcount; i++)
341 ucontrol->value.integer.value[i] = ctl->value[i];
342 spin_unlock_irqrestore(&emu->reg_lock, flags);
343 return 0;
344}
345
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100346static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100348 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
349 struct snd_emu10k1_fx8010_ctl *ctl =
350 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 unsigned long flags;
352 unsigned int nval, val;
353 unsigned int i, j;
354 int change = 0;
355
356 spin_lock_irqsave(&emu->reg_lock, flags);
357 for (i = 0; i < ctl->vcount; i++) {
358 nval = ucontrol->value.integer.value[i];
359 if (nval < ctl->min)
360 nval = ctl->min;
361 if (nval > ctl->max)
362 nval = ctl->max;
363 if (nval != ctl->value[i])
364 change = 1;
365 val = ctl->value[i] = nval;
366 switch (ctl->translation) {
367 case EMU10K1_GPR_TRANSLATION_NONE:
368 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
369 break;
370 case EMU10K1_GPR_TRANSLATION_TABLE100:
371 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
372 break;
373 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200374 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
375 change = -EIO;
376 goto __error;
377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 for (j = 0; j < 5; j++)
379 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
380 break;
381 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200382 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
383 change = -EIO;
384 goto __error;
385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 for (j = 0; j < 5; j++)
387 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
388 break;
389 case EMU10K1_GPR_TRANSLATION_ONOFF:
390 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
391 break;
392 }
393 }
394 __error:
395 spin_unlock_irqrestore(&emu->reg_lock, flags);
396 return change;
397}
398
399/*
400 * Interrupt handler
401 */
402
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100403static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100405 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 irq = emu->fx8010.irq_handlers;
408 while (irq) {
409 nirq = irq->next; /* irq ptr can be removed from list */
410 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
411 if (irq->handler)
412 irq->handler(emu, irq->private_data);
413 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
414 }
415 irq = nirq;
416 }
417}
418
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100419int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
420 snd_fx8010_irq_handler_t *handler,
421 unsigned char gpr_running,
422 void *private_data,
423 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100425 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 unsigned long flags;
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
429 if (irq == NULL)
430 return -ENOMEM;
431 irq->handler = handler;
432 irq->gpr_running = gpr_running;
433 irq->private_data = private_data;
434 irq->next = NULL;
435 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
436 if (emu->fx8010.irq_handlers == NULL) {
437 emu->fx8010.irq_handlers = irq;
438 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
439 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
440 } else {
441 irq->next = emu->fx8010.irq_handlers;
442 emu->fx8010.irq_handlers = irq;
443 }
444 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
445 if (r_irq)
446 *r_irq = irq;
447 return 0;
448}
449
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100450int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
451 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100453 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 unsigned long flags;
455
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
457 if ((tmp = emu->fx8010.irq_handlers) == irq) {
458 emu->fx8010.irq_handlers = tmp->next;
459 if (emu->fx8010.irq_handlers == NULL) {
460 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
461 emu->dsp_interrupt = NULL;
462 }
463 } else {
464 while (tmp && tmp->next != irq)
465 tmp = tmp->next;
466 if (tmp)
467 tmp->next = tmp->next->next;
468 }
469 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
470 kfree(irq);
471 return 0;
472}
473
474/*************************************************************************
475 * EMU10K1 effect manager
476 *************************************************************************/
477
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100478static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
479 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 u32 op, u32 r, u32 a, u32 x, u32 y)
481{
482 u_int32_t *code;
483 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200484 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 set_bit(*ptr, icode->code_valid);
486 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
487 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
488 (*ptr)++;
489}
490
491#define OP(icode, ptr, op, r, a, x, y) \
492 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
493
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100494static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
495 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 u32 op, u32 r, u32 a, u32 x, u32 y)
497{
498 u_int32_t *code;
499 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200500 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 set_bit(*ptr, icode->code_valid);
502 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
503 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
504 (*ptr)++;
505}
506
507#define A_OP(icode, ptr, op, r, a, x, y) \
508 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
509
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100510static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511{
512 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
513 snd_emu10k1_ptr_write(emu, pc, 0, data);
514}
515
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100516unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
519 return snd_emu10k1_ptr_read(emu, pc, 0);
520}
521
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100522static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
523 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 int gpr;
526 u32 val;
527
528 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
529 if (!test_bit(gpr, icode->gpr_valid))
530 continue;
531 if (get_user(val, &icode->gpr_map[gpr]))
532 return -EFAULT;
533 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
534 }
535 return 0;
536}
537
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100538static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
539 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 int gpr;
542 u32 val;
543
544 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
545 set_bit(gpr, icode->gpr_valid);
546 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
547 if (put_user(val, &icode->gpr_map[gpr]))
548 return -EFAULT;
549 }
550 return 0;
551}
552
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100553static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
554 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
556 int tram;
557 u32 addr, val;
558
559 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
560 if (!test_bit(tram, icode->tram_valid))
561 continue;
562 if (get_user(val, &icode->tram_data_map[tram]) ||
563 get_user(addr, &icode->tram_addr_map[tram]))
564 return -EFAULT;
565 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
566 if (!emu->audigy) {
567 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
568 } else {
569 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
570 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
571 }
572 }
573 return 0;
574}
575
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100576static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
577 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578{
579 int tram;
580 u32 val, addr;
581
582 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
583 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
584 set_bit(tram, icode->tram_valid);
585 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
586 if (!emu->audigy) {
587 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
588 } else {
589 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
590 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
591 }
592 if (put_user(val, &icode->tram_data_map[tram]) ||
593 put_user(addr, &icode->tram_addr_map[tram]))
594 return -EFAULT;
595 }
596 return 0;
597}
598
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100599static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
600 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 u32 pc, lo, hi;
603
604 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
605 if (!test_bit(pc / 2, icode->code_valid))
606 continue;
607 if (get_user(lo, &icode->code[pc + 0]) ||
608 get_user(hi, &icode->code[pc + 1]))
609 return -EFAULT;
610 snd_emu10k1_efx_write(emu, pc + 0, lo);
611 snd_emu10k1_efx_write(emu, pc + 1, hi);
612 }
613 return 0;
614}
615
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100616static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
617 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 u32 pc;
620
621 memset(icode->code_valid, 0, sizeof(icode->code_valid));
622 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
623 set_bit(pc / 2, icode->code_valid);
624 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
625 return -EFAULT;
626 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
627 return -EFAULT;
628 }
629 return 0;
630}
631
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100632static struct snd_emu10k1_fx8010_ctl *
633snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100635 struct snd_emu10k1_fx8010_ctl *ctl;
636 struct snd_kcontrol *kcontrol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 struct list_head *list;
638
639 list_for_each(list, &emu->fx8010.gpr_ctl) {
640 ctl = emu10k1_gpr_ctl(list);
641 kcontrol = ctl->kcontrol;
642 if (kcontrol->id.iface == id->iface &&
643 !strcmp(kcontrol->id.name, id->name) &&
644 kcontrol->id.index == id->index)
645 return ctl;
646 }
647 return NULL;
648}
649
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100650static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
651 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
653 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100654 struct snd_ctl_elem_id __user *_id;
655 struct snd_ctl_elem_id id;
656 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
657 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 int err;
659
660 for (i = 0, _id = icode->gpr_del_controls;
661 i < icode->gpr_del_control_count; i++, _id++) {
662 if (copy_from_user(&id, _id, sizeof(id)))
663 return -EFAULT;
664 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
665 return -ENOENT;
666 }
667 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
668 if (! gctl)
669 return -ENOMEM;
670 err = 0;
671 for (i = 0, _gctl = icode->gpr_add_controls;
672 i < icode->gpr_add_control_count; i++, _gctl++) {
673 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
674 err = -EFAULT;
675 goto __error;
676 }
677 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
678 continue;
679 down_read(&emu->card->controls_rwsem);
680 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
681 up_read(&emu->card->controls_rwsem);
682 err = -EEXIST;
683 goto __error;
684 }
685 up_read(&emu->card->controls_rwsem);
686 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
687 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
688 err = -EINVAL;
689 goto __error;
690 }
691 }
692 for (i = 0, _gctl = icode->gpr_list_controls;
693 i < icode->gpr_list_control_count; i++, _gctl++) {
694 /* FIXME: we need to check the WRITE access */
695 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
696 err = -EFAULT;
697 goto __error;
698 }
699 }
700 __error:
701 kfree(gctl);
702 return err;
703}
704
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100705static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100707 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100709 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 kctl->private_value = 0;
711 list_del(&ctl->list);
712 kfree(ctl);
713}
714
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100715static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
716 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100719 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
720 struct snd_emu10k1_fx8010_control_gpr *gctl;
721 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
722 struct snd_kcontrol_new knew;
723 struct snd_kcontrol *kctl;
724 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 int err = 0;
726
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100727 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
729 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
730 if (!val || !gctl || !nctl) {
731 err = -ENOMEM;
732 goto __error;
733 }
734
735 for (i = 0, _gctl = icode->gpr_add_controls;
736 i < icode->gpr_add_control_count; i++, _gctl++) {
737 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
738 err = -EFAULT;
739 goto __error;
740 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200741 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
742 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
743 err = -EINVAL;
744 goto __error;
745 }
746 if (! gctl->id.name[0]) {
747 err = -EINVAL;
748 goto __error;
749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
751 memset(&knew, 0, sizeof(knew));
752 knew.iface = gctl->id.iface;
753 knew.name = gctl->id.name;
754 knew.index = gctl->id.index;
755 knew.device = gctl->id.device;
756 knew.subdevice = gctl->id.subdevice;
757 knew.info = snd_emu10k1_gpr_ctl_info;
758 knew.get = snd_emu10k1_gpr_ctl_get;
759 knew.put = snd_emu10k1_gpr_ctl_put;
760 memset(nctl, 0, sizeof(*nctl));
761 nctl->vcount = gctl->vcount;
762 nctl->count = gctl->count;
763 for (j = 0; j < 32; j++) {
764 nctl->gpr[j] = gctl->gpr[j];
765 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
766 val->value.integer.value[j] = gctl->value[j];
767 }
768 nctl->min = gctl->min;
769 nctl->max = gctl->max;
770 nctl->translation = gctl->translation;
771 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100772 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (ctl == NULL) {
774 err = -ENOMEM;
775 goto __error;
776 }
777 knew.private_value = (unsigned long)ctl;
778 *ctl = *nctl;
779 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
780 kfree(ctl);
781 goto __error;
782 }
783 kctl->private_free = snd_emu10k1_ctl_private_free;
784 ctl->kcontrol = kctl;
785 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
786 } else {
787 /* overwrite */
788 nctl->list = ctl->list;
789 nctl->kcontrol = ctl->kcontrol;
790 *ctl = *nctl;
791 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
792 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
793 }
794 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
795 }
796 __error:
797 kfree(nctl);
798 kfree(gctl);
799 kfree(val);
800 return err;
801}
802
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100803static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
804 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100807 struct snd_ctl_elem_id id;
808 struct snd_ctl_elem_id __user *_id;
809 struct snd_emu10k1_fx8010_ctl *ctl;
810 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 for (i = 0, _id = icode->gpr_del_controls;
813 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200814 if (copy_from_user(&id, _id, sizeof(id)))
815 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 down_write(&card->controls_rwsem);
817 ctl = snd_emu10k1_look_for_ctl(emu, &id);
818 if (ctl)
819 snd_ctl_remove(card, ctl->kcontrol);
820 up_write(&card->controls_rwsem);
821 }
822 return 0;
823}
824
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100825static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
826 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 unsigned int i = 0, j;
829 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100830 struct snd_emu10k1_fx8010_control_gpr *gctl;
831 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
832 struct snd_emu10k1_fx8010_ctl *ctl;
833 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 struct list_head *list;
835
836 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
837 if (! gctl)
838 return -ENOMEM;
839
840 _gctl = icode->gpr_list_controls;
841 list_for_each(list, &emu->fx8010.gpr_ctl) {
842 ctl = emu10k1_gpr_ctl(list);
843 total++;
844 if (_gctl && i < icode->gpr_list_control_count) {
845 memset(gctl, 0, sizeof(*gctl));
846 id = &ctl->kcontrol->id;
847 gctl->id.iface = id->iface;
848 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
849 gctl->id.index = id->index;
850 gctl->id.device = id->device;
851 gctl->id.subdevice = id->subdevice;
852 gctl->vcount = ctl->vcount;
853 gctl->count = ctl->count;
854 for (j = 0; j < 32; j++) {
855 gctl->gpr[j] = ctl->gpr[j];
856 gctl->value[j] = ctl->value[j];
857 }
858 gctl->min = ctl->min;
859 gctl->max = ctl->max;
860 gctl->translation = ctl->translation;
861 if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
862 kfree(gctl);
863 return -EFAULT;
864 }
865 _gctl++;
866 i++;
867 }
868 }
869 icode->gpr_list_control_total = total;
870 kfree(gctl);
871 return 0;
872}
873
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100874static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
875 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 int err = 0;
878
Ingo Molnar62932df2006-01-16 16:34:20 +0100879 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
881 goto __error;
882 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
883 /* stop FX processor - this may be dangerous, but it's better to miss
884 some samples than generate wrong ones - [jk] */
885 if (emu->audigy)
886 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
887 else
888 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
889 /* ok, do the main job */
890 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
891 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
892 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
893 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
894 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
895 goto __error;
896 /* start FX processor when the DSP code is updated */
897 if (emu->audigy)
898 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
899 else
900 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
901 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100902 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return err;
904}
905
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100906static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
907 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
909 int err;
910
Ingo Molnar62932df2006-01-16 16:34:20 +0100911 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
913 /* ok, do the main job */
914 err = snd_emu10k1_gpr_peek(emu, icode);
915 if (err >= 0)
916 err = snd_emu10k1_tram_peek(emu, icode);
917 if (err >= 0)
918 err = snd_emu10k1_code_peek(emu, icode);
919 if (err >= 0)
920 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100921 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 return err;
923}
924
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100925static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
926 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
928 unsigned int i;
929 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100930 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
932 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
933 return -EINVAL;
934 if (ipcm->channels > 32)
935 return -EINVAL;
936 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100937 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 spin_lock_irq(&emu->reg_lock);
939 if (pcm->opened) {
940 err = -EBUSY;
941 goto __error;
942 }
943 if (ipcm->channels == 0) { /* remove */
944 pcm->valid = 0;
945 } else {
946 /* FIXME: we need to add universal code to the PCM transfer routine */
947 if (ipcm->channels != 2) {
948 err = -EINVAL;
949 goto __error;
950 }
951 pcm->valid = 1;
952 pcm->opened = 0;
953 pcm->channels = ipcm->channels;
954 pcm->tram_start = ipcm->tram_start;
955 pcm->buffer_size = ipcm->buffer_size;
956 pcm->gpr_size = ipcm->gpr_size;
957 pcm->gpr_count = ipcm->gpr_count;
958 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
959 pcm->gpr_ptr = ipcm->gpr_ptr;
960 pcm->gpr_trigger = ipcm->gpr_trigger;
961 pcm->gpr_running = ipcm->gpr_running;
962 for (i = 0; i < pcm->channels; i++)
963 pcm->etram[i] = ipcm->etram[i];
964 }
965 __error:
966 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +0100967 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return err;
969}
970
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100971static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
972 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 unsigned int i;
975 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100976 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
979 return -EINVAL;
980 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100981 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 spin_lock_irq(&emu->reg_lock);
983 ipcm->channels = pcm->channels;
984 ipcm->tram_start = pcm->tram_start;
985 ipcm->buffer_size = pcm->buffer_size;
986 ipcm->gpr_size = pcm->gpr_size;
987 ipcm->gpr_ptr = pcm->gpr_ptr;
988 ipcm->gpr_count = pcm->gpr_count;
989 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
990 ipcm->gpr_trigger = pcm->gpr_trigger;
991 ipcm->gpr_running = pcm->gpr_running;
992 for (i = 0; i < pcm->channels; i++)
993 ipcm->etram[i] = pcm->etram[i];
994 ipcm->res1 = ipcm->res2 = 0;
995 ipcm->pad = 0;
996 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +0100997 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 return err;
999}
1000
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001001#define SND_EMU10K1_GPR_CONTROLS 44
1002#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1004#define SND_EMU10K1_CAPTURE_CHANNELS 4
1005
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001006static void __devinit
1007snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1008 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
1010 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1011 strcpy(ctl->id.name, name);
1012 ctl->vcount = ctl->count = 1;
1013 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1014 ctl->min = 0;
1015 ctl->max = 100;
1016 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1017}
1018
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001019static void __devinit
1020snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1021 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022{
1023 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1024 strcpy(ctl->id.name, name);
1025 ctl->vcount = ctl->count = 2;
1026 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1027 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1028 ctl->min = 0;
1029 ctl->max = 100;
1030 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1031}
1032
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001033static void __devinit
1034snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1035 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
1037 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1038 strcpy(ctl->id.name, name);
1039 ctl->vcount = ctl->count = 1;
1040 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1041 ctl->min = 0;
1042 ctl->max = 1;
1043 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1044}
1045
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001046static void __devinit
1047snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1048 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
1050 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1051 strcpy(ctl->id.name, name);
1052 ctl->vcount = ctl->count = 2;
1053 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1054 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1055 ctl->min = 0;
1056 ctl->max = 1;
1057 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1058}
1059
1060
1061/*
1062 * initial DSP configuration for Audigy
1063 */
1064
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001065static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066{
1067 int err, i, z, gpr, nctl;
1068 const int playback = 10;
1069 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1070 const int stereo_mix = capture + 2;
1071 const int tmp = 0x88;
1072 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001073 struct snd_emu10k1_fx8010_code *icode = NULL;
1074 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 u32 *gpr_map;
1076 mm_segment_t seg;
1077
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001078 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001079 (icode->gpr_map = (u_int32_t __user *)
1080 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1081 GFP_KERNEL)) == NULL ||
1082 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1083 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 err = -ENOMEM;
1085 goto __err;
1086 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001087 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 icode->tram_data_map = icode->gpr_map + 512;
1090 icode->tram_addr_map = icode->tram_data_map + 256;
1091 icode->code = icode->tram_addr_map + 256;
1092
1093 /* clear free GPRs */
1094 for (i = 0; i < 512; i++)
1095 set_bit(i, icode->gpr_valid);
1096
1097 /* clear TRAM data & address lines */
1098 for (i = 0; i < 256; i++)
1099 set_bit(i, icode->tram_valid);
1100
1101 strcpy(icode->name, "Audigy DSP code for ALSA");
1102 ptr = 0;
1103 nctl = 0;
1104 gpr = stereo_mix + 10;
1105
1106 /* stop FX processor */
1107 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1108
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001109#if 0
1110 /* FIX: jcd test */
1111 for (z = 0; z < 80; z=z+2) {
1112 A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
1113 A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
1114 }
1115#endif /* jcd test */
1116#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* PCM front Playback Volume (independent from stereo mix) */
1118 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1119 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1120 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1121 gpr += 2;
1122
1123 /* PCM Surround Playback (independent from stereo mix) */
1124 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1125 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1126 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1127 gpr += 2;
1128
1129 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001130 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1132 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1133 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1134 gpr += 2;
1135 }
1136
1137 /* PCM Center Playback (independent from stereo mix) */
1138 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1139 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1140 gpr++;
1141
1142 /* PCM LFE Playback (independent from stereo mix) */
1143 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1144 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1145 gpr++;
1146
1147 /*
1148 * Stereo Mix
1149 */
1150 /* Wave (PCM) Playback Volume (will be renamed later) */
1151 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1152 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1153 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1154 gpr += 2;
1155
1156 /* Synth Playback */
1157 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1158 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1159 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1160 gpr += 2;
1161
1162 /* Wave (PCM) Capture */
1163 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1164 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1165 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1166 gpr += 2;
1167
1168 /* Synth Capture */
1169 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1170 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1171 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1172 gpr += 2;
1173
1174 /*
1175 * inputs
1176 */
1177#define A_ADD_VOLUME_IN(var,vol,input) \
1178A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1179
1180 /* AC'97 Playback Volume - used only for mic (renamed later) */
1181 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1182 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1183 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1184 gpr += 2;
1185 /* AC'97 Capture Volume - used only for mic */
1186 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1187 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1188 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1189 gpr += 2;
1190
1191 /* mic capture buffer */
1192 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1193
1194 /* Audigy CD Playback Volume */
1195 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1196 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1197 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001198 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 gpr, 0);
1200 gpr += 2;
1201 /* Audigy CD Capture Volume */
1202 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1203 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1204 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001205 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 gpr, 0);
1207 gpr += 2;
1208
1209 /* Optical SPDIF Playback Volume */
1210 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1211 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001212 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 gpr += 2;
1214 /* Optical SPDIF Capture Volume */
1215 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1216 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001217 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 gpr += 2;
1219
1220 /* Line2 Playback Volume */
1221 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1222 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1223 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001224 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 gpr, 0);
1226 gpr += 2;
1227 /* Line2 Capture Volume */
1228 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1229 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1230 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001231 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 gpr, 0);
1233 gpr += 2;
1234
1235 /* Philips ADC Playback Volume */
1236 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1237 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1238 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1239 gpr += 2;
1240 /* Philips ADC Capture Volume */
1241 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1242 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1243 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1244 gpr += 2;
1245
1246 /* Aux2 Playback Volume */
1247 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1248 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1249 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001250 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 gpr, 0);
1252 gpr += 2;
1253 /* Aux2 Capture Volume */
1254 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1255 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1256 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001257 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 gpr, 0);
1259 gpr += 2;
1260
1261 /* Stereo Mix Front Playback Volume */
1262 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1263 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1264 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1265 gpr += 2;
1266
1267 /* Stereo Mix Surround Playback */
1268 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1269 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1270 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1271 gpr += 2;
1272
1273 /* Stereo Mix Center Playback */
1274 /* Center = sub = Left/2 + Right/2 */
1275 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1276 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1277 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1278 gpr++;
1279
1280 /* Stereo Mix LFE Playback */
1281 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1282 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1283 gpr++;
1284
Lee Revell2b637da2005-03-30 13:51:18 +02001285 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 /* Stereo Mix Side Playback */
1287 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1288 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1289 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1290 gpr += 2;
1291 }
1292
1293 /*
1294 * outputs
1295 */
1296#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1297#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1298 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1299
1300#define _A_SWITCH(icode, ptr, dst, src, sw) \
1301 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1302#define A_SWITCH(icode, ptr, dst, src, sw) \
1303 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1304#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1305 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1306#define A_SWITCH_NEG(icode, ptr, dst, src) \
1307 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1308
1309
1310 /*
1311 * Process tone control
1312 */
1313 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1314 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1315 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */
1316 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */
1317 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1318 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */
Lee Revell2b637da2005-03-30 13:51:18 +02001319 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */
1321 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */
1322 }
1323
1324
1325 ctl = &controls[nctl + 0];
1326 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1327 strcpy(ctl->id.name, "Tone Control - Bass");
1328 ctl->vcount = 2;
1329 ctl->count = 10;
1330 ctl->min = 0;
1331 ctl->max = 40;
1332 ctl->value[0] = ctl->value[1] = 20;
1333 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1334 ctl = &controls[nctl + 1];
1335 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1336 strcpy(ctl->id.name, "Tone Control - Treble");
1337 ctl->vcount = 2;
1338 ctl->count = 10;
1339 ctl->min = 0;
1340 ctl->max = 40;
1341 ctl->value[0] = ctl->value[1] = 20;
1342 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1343
1344#define BASS_GPR 0x8c
1345#define TREBLE_GPR 0x96
1346
1347 for (z = 0; z < 5; z++) {
1348 int j;
1349 for (j = 0; j < 2; j++) {
1350 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1351 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1352 }
1353 }
1354 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1355 int j, k, l, d;
1356 for (j = 0; j < 2; j++) { /* left/right */
1357 k = 0xb0 + (z * 8) + (j * 4);
1358 l = 0xe0 + (z * 8) + (j * 4);
1359 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1360
1361 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1362 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1363 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1364 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1365 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1366 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1367
1368 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1369 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1370 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1371 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1372 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1373 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1374
1375 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1376
1377 if (z == 2) /* center */
1378 break;
1379 }
1380 }
1381 nctl += 2;
1382
1383#undef BASS_GPR
1384#undef TREBLE_GPR
1385
1386 for (z = 0; z < 8; z++) {
1387 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1388 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1389 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1390 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1391 }
1392 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1393 gpr += 2;
1394
1395 /* Master volume (will be renamed later) */
1396 A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS));
1397 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS));
1398 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS));
1399 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS));
1400 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS));
1401 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS));
1402 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS));
1403 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS));
1404 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1405 gpr += 2;
1406
1407 /* analog speakers */
1408 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1409 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1410 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1411 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001412 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1414
1415 /* headphone */
1416 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1417
1418 /* digital outputs */
1419 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
1420
1421 /* IEC958 Optical Raw Playback Switch */
1422 gpr_map[gpr++] = 0;
1423 gpr_map[gpr++] = 0x1008;
1424 gpr_map[gpr++] = 0xffff0000;
1425 for (z = 0; z < 2; z++) {
1426 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1427 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1428 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1429 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1430 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1431 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1432 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1433 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1434 /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
Takashi Iwai99b359b2005-10-20 18:26:44 +02001435 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1437 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1438 } else {
1439 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1440 }
1441 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001442 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 gpr += 2;
1444
1445 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1446 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1447 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1448
1449 /* ADC buffer */
1450#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1451 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1452#else
1453 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1454 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1455#endif
1456
1457 /* EFX capture - capture the 16 EXTINs */
1458 for (z = 0; z < 16; z++) {
1459 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1460 }
1461
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001462#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 /*
1464 * ok, set up done..
1465 */
1466
1467 if (gpr > tmp) {
1468 snd_BUG();
1469 err = -EIO;
1470 goto __err;
1471 }
1472 /* clear remaining instruction memory */
1473 while (ptr < 0x400)
1474 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1475
1476 seg = snd_enter_user();
1477 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001478 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 err = snd_emu10k1_icode_poke(emu, icode);
1480 snd_leave_user(seg);
1481
1482 __err:
1483 kfree(controls);
1484 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001485 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 kfree(icode);
1487 }
1488 return err;
1489}
1490
1491
1492/*
1493 * initial DSP configuration for Emu10k1
1494 */
1495
1496/* when volume = max, then copy only to avoid volume modification */
1497/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001498static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
1500 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1501 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1502 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1503 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1504}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001505static void __devinit _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1508 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1509 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1510 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1511 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1512}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001513static void __devinit _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1516 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1517 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1518 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1519 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1520}
1521
1522#define VOLUME(icode, ptr, dst, src, vol) \
1523 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1524#define VOLUME_IN(icode, ptr, dst, src, vol) \
1525 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1526#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1527 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1528#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1529 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1530#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1531 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1532#define _SWITCH(icode, ptr, dst, src, sw) \
1533 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1534#define SWITCH(icode, ptr, dst, src, sw) \
1535 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1536#define SWITCH_IN(icode, ptr, dst, src, sw) \
1537 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1538#define _SWITCH_NEG(icode, ptr, dst, src) \
1539 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1540#define SWITCH_NEG(icode, ptr, dst, src) \
1541 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1542
1543
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001544static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 int err, i, z, gpr, tmp, playback, capture;
1547 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001548 struct snd_emu10k1_fx8010_code *icode;
1549 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1550 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 u32 *gpr_map;
1552 mm_segment_t seg;
1553
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001554 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001556 if ((icode->gpr_map = (u_int32_t __user *)
1557 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1558 GFP_KERNEL)) == NULL ||
1559 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1560 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1561 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001562 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 err = -ENOMEM;
1564 goto __err;
1565 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001566 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 icode->tram_data_map = icode->gpr_map + 256;
1569 icode->tram_addr_map = icode->tram_data_map + 160;
1570 icode->code = icode->tram_addr_map + 160;
1571
1572 /* clear free GPRs */
1573 for (i = 0; i < 256; i++)
1574 set_bit(i, icode->gpr_valid);
1575
1576 /* clear TRAM data & address lines */
1577 for (i = 0; i < 160; i++)
1578 set_bit(i, icode->tram_valid);
1579
1580 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1581 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001582 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 playback = SND_EMU10K1_INPUTS;
1584 /* we have 6 playback channels and tone control doubles */
1585 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1586 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1587 tmp = 0x88; /* we need 4 temporary GPR */
1588 /* from 0x8c to 0xff is the area for tone control */
1589
1590 /* stop FX processor */
1591 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1592
1593 /*
1594 * Process FX Buses
1595 */
1596 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1597 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1598 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1599 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1600 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1601 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1602 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1603 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1604 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1605 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001606 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1607 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
1609 /* Raw S/PDIF PCM */
1610 ipcm->substream = 0;
1611 ipcm->channels = 2;
1612 ipcm->tram_start = 0;
1613 ipcm->buffer_size = (64 * 1024) / 2;
1614 ipcm->gpr_size = gpr++;
1615 ipcm->gpr_ptr = gpr++;
1616 ipcm->gpr_count = gpr++;
1617 ipcm->gpr_tmpcount = gpr++;
1618 ipcm->gpr_trigger = gpr++;
1619 ipcm->gpr_running = gpr++;
1620 ipcm->etram[0] = 0;
1621 ipcm->etram[1] = 1;
1622
1623 gpr_map[gpr + 0] = 0xfffff000;
1624 gpr_map[gpr + 1] = 0xffff0000;
1625 gpr_map[gpr + 2] = 0x70000000;
1626 gpr_map[gpr + 3] = 0x00000007;
1627 gpr_map[gpr + 4] = 0x001f << 11;
1628 gpr_map[gpr + 5] = 0x001c << 11;
1629 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1630 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1631 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1632 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1633 gpr_map[gpr + 10] = 1<<11;
1634 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1635 gpr_map[gpr + 12] = 0;
1636
1637 /* if the trigger flag is not set, skip */
1638 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1639 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1640 /* if the running flag is set, we're running */
1641 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1642 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1643 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1644 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1645 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1646 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1647 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1648
1649 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1650 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1651 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1652 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1653
1654 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1655 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1656 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1657 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1658 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1659
1660 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1661 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1662 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1663 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1664 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1665
1666 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1667 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1668 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1669 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1670 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1671
1672 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1673 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1674 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1675 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1676 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1677
1678 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1679 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1680
1681 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1682 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1683
1684 /* 24: */
1685 gpr += 13;
1686
1687 /* Wave Playback Volume */
1688 for (z = 0; z < 2; z++)
1689 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1690 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1691 gpr += 2;
1692
1693 /* Wave Surround Playback Volume */
1694 for (z = 0; z < 2; z++)
1695 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1696 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1697 gpr += 2;
1698
1699 /* Wave Center/LFE Playback Volume */
1700 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1701 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1702 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1703 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1704 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1705 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1706
1707 /* Wave Capture Volume + Switch */
1708 for (z = 0; z < 2; z++) {
1709 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1710 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1711 }
1712 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1713 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1714 gpr += 4;
1715
1716 /* Synth Playback Volume */
1717 for (z = 0; z < 2; z++)
1718 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1719 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1720 gpr += 2;
1721
1722 /* Synth Capture Volume + Switch */
1723 for (z = 0; z < 2; z++) {
1724 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1725 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1726 }
1727 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1728 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1729 gpr += 4;
1730
1731 /* Surround Digital Playback Volume (renamed later without Digital) */
1732 for (z = 0; z < 2; z++)
1733 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1734 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1735 gpr += 2;
1736
1737 /* Surround Capture Volume + Switch */
1738 for (z = 0; z < 2; z++) {
1739 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1740 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1741 }
1742 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1743 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1744 gpr += 4;
1745
1746 /* Center Playback Volume (renamed later without Digital) */
1747 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1748 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1749
1750 /* LFE Playback Volume + Switch (renamed later without Digital) */
1751 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1752 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1753
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001754 /* Front Playback Volume */
1755 for (z = 0; z < 2; z++)
1756 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1757 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1758 gpr += 2;
1759
1760 /* Front Capture Volume + Switch */
1761 for (z = 0; z < 2; z++) {
1762 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1763 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1764 }
1765 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
1766 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
1767 gpr += 3;
1768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 /*
1770 * Process inputs
1771 */
1772
1773 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
1774 /* AC'97 Playback Volume */
1775 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
1776 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
1777 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
1778 /* AC'97 Capture Volume */
1779 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
1780 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
1781 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
1782 }
1783
1784 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
1785 /* IEC958 TTL Playback Volume */
1786 for (z = 0; z < 2; z++)
1787 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001788 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 gpr += 2;
1790
1791 /* IEC958 TTL Capture Volume + Switch */
1792 for (z = 0; z < 2; z++) {
1793 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
1794 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1795 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001796 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
1797 snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 gpr += 4;
1799 }
1800
1801 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
1802 /* Zoom Video Playback Volume */
1803 for (z = 0; z < 2; z++)
1804 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
1805 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
1806 gpr += 2;
1807
1808 /* Zoom Video Capture Volume + Switch */
1809 for (z = 0; z < 2; z++) {
1810 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
1811 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1812 }
1813 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
1814 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
1815 gpr += 4;
1816 }
1817
1818 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
1819 /* IEC958 Optical Playback Volume */
1820 for (z = 0; z < 2; z++)
1821 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001822 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 gpr += 2;
1824
1825 /* IEC958 Optical Capture Volume */
1826 for (z = 0; z < 2; z++) {
1827 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
1828 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1829 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001830 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
1831 snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 gpr += 4;
1833 }
1834
1835 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
1836 /* Line LiveDrive Playback Volume */
1837 for (z = 0; z < 2; z++)
1838 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
1839 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
1840 gpr += 2;
1841
1842 /* Line LiveDrive Capture Volume + Switch */
1843 for (z = 0; z < 2; z++) {
1844 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
1845 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1846 }
1847 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
1848 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
1849 gpr += 4;
1850 }
1851
1852 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
1853 /* IEC958 Coax Playback Volume */
1854 for (z = 0; z < 2; z++)
1855 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001856 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 gpr += 2;
1858
1859 /* IEC958 Coax Capture Volume + Switch */
1860 for (z = 0; z < 2; z++) {
1861 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
1862 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1863 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001864 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
1865 snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 gpr += 4;
1867 }
1868
1869 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
1870 /* Line LiveDrive Playback Volume */
1871 for (z = 0; z < 2; z++)
1872 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
1873 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
1874 controls[i-1].id.index = 1;
1875 gpr += 2;
1876
1877 /* Line LiveDrive Capture Volume */
1878 for (z = 0; z < 2; z++) {
1879 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
1880 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1881 }
1882 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
1883 controls[i-1].id.index = 1;
1884 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
1885 controls[i-1].id.index = 1;
1886 gpr += 4;
1887 }
1888
1889 /*
1890 * Process tone control
1891 */
1892 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
1893 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
1894 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
1895 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
1896 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
1897 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
1898
1899 ctl = &controls[i + 0];
1900 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1901 strcpy(ctl->id.name, "Tone Control - Bass");
1902 ctl->vcount = 2;
1903 ctl->count = 10;
1904 ctl->min = 0;
1905 ctl->max = 40;
1906 ctl->value[0] = ctl->value[1] = 20;
1907 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1908 ctl = &controls[i + 1];
1909 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1910 strcpy(ctl->id.name, "Tone Control - Treble");
1911 ctl->vcount = 2;
1912 ctl->count = 10;
1913 ctl->min = 0;
1914 ctl->max = 40;
1915 ctl->value[0] = ctl->value[1] = 20;
1916 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1917
1918#define BASS_GPR 0x8c
1919#define TREBLE_GPR 0x96
1920
1921 for (z = 0; z < 5; z++) {
1922 int j;
1923 for (j = 0; j < 2; j++) {
1924 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1925 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1926 }
1927 }
1928 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
1929 int j, k, l, d;
1930 for (j = 0; j < 2; j++) { /* left/right */
1931 k = 0xa0 + (z * 8) + (j * 4);
1932 l = 0xd0 + (z * 8) + (j * 4);
1933 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1934
1935 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
1936 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
1937 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
1938 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
1939 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
1940 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
1941
1942 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
1943 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
1944 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
1945 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
1946 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
1947 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
1948
1949 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
1950
1951 if (z == 2) /* center */
1952 break;
1953 }
1954 }
1955 i += 2;
1956
1957#undef BASS_GPR
1958#undef TREBLE_GPR
1959
1960 for (z = 0; z < 6; z++) {
1961 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1962 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1963 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1964 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1965 }
1966 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
1967 gpr += 2;
1968
1969 /*
1970 * Process outputs
1971 */
1972 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
1973 /* AC'97 Playback Volume */
1974
1975 for (z = 0; z < 2; z++)
1976 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
1977 }
1978
1979 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
1980 /* IEC958 Optical Raw Playback Switch */
1981
1982 for (z = 0; z < 2; z++) {
1983 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
1984 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1985 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1986 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1987#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1988 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1989#endif
1990 }
1991
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001992 snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 gpr += 2;
1994 }
1995
1996 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
1997 /* Headphone Playback Volume */
1998
1999 for (z = 0; z < 2; z++) {
2000 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2001 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2002 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2003 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2004 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2005 }
2006
2007 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2008 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2009 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2010 controls[i-1].id.index = 1;
2011 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2012 controls[i-1].id.index = 1;
2013
2014 gpr += 4;
2015 }
2016
2017 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2018 for (z = 0; z < 2; z++)
2019 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2020
2021 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2022 for (z = 0; z < 2; z++)
2023 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2024
2025 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2026#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2027 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2028 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2029#else
2030 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2031 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2032#endif
2033 }
2034
2035 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2036#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2037 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2038 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2039#else
2040 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2041 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2042#endif
2043 }
2044
2045#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2046 for (z = 0; z < 2; z++)
2047 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2048#endif
2049
2050 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2051 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2052
2053 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002054 if (emu->card_capabilities->sblive51) {
2055 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2056 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2057 *
2058 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2059 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2060 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2061 * channel. Multitrack recorders will still see the center/lfe output signal
2062 * on the second and third channels.
2063 */
2064 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2065 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2066 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2067 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2068 for (z = 4; z < 14; z++)
2069 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2070 } else {
2071 for (z = 0; z < 16; z++)
2072 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 }
Lee Revell2b637da2005-03-30 13:51:18 +02002074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
2076 if (gpr > tmp) {
2077 snd_BUG();
2078 err = -EIO;
2079 goto __err;
2080 }
2081 if (i > SND_EMU10K1_GPR_CONTROLS) {
2082 snd_BUG();
2083 err = -EIO;
2084 goto __err;
2085 }
2086
2087 /* clear remaining instruction memory */
2088 while (ptr < 0x200)
2089 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2090
2091 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2092 goto __err;
2093 seg = snd_enter_user();
2094 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002095 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 err = snd_emu10k1_icode_poke(emu, icode);
2097 snd_leave_user(seg);
2098 if (err >= 0)
2099 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2100 __err:
2101 kfree(ipcm);
2102 kfree(controls);
2103 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002104 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 kfree(icode);
2106 }
2107 return err;
2108}
2109
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002110int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111{
Takashi Iwai09668b42005-11-17 16:14:10 +01002112 spin_lock_init(&emu->fx8010.irq_lock);
2113 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 if (emu->audigy)
2115 return _snd_emu10k1_audigy_init_efx(emu);
2116 else
2117 return _snd_emu10k1_init_efx(emu);
2118}
2119
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002120void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121{
2122 /* stop processor */
2123 if (emu->audigy)
2124 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2125 else
2126 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2127}
2128
2129#if 0 // FIXME: who use them?
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002130int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002132 if (output < 0 || output >= 6)
2133 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2135 return 0;
2136}
2137
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002138int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002140 if (output < 0 || output >= 6)
2141 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2143 return 0;
2144}
2145#endif
2146
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002147int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148{
2149 u8 size_reg = 0;
2150
2151 /* size is in samples */
2152 if (size != 0) {
2153 size = (size - 1) >> 13;
2154
2155 while (size) {
2156 size >>= 1;
2157 size_reg++;
2158 }
2159 size = 0x2000 << size_reg;
2160 }
2161 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2162 return 0;
2163 spin_lock_irq(&emu->emu_lock);
2164 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2165 spin_unlock_irq(&emu->emu_lock);
2166 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2167 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2168 if (emu->fx8010.etram_pages.area != NULL) {
2169 snd_dma_free_pages(&emu->fx8010.etram_pages);
2170 emu->fx8010.etram_pages.area = NULL;
2171 emu->fx8010.etram_pages.bytes = 0;
2172 }
2173
2174 if (size > 0) {
2175 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2176 size * 2, &emu->fx8010.etram_pages) < 0)
2177 return -ENOMEM;
2178 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2179 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2180 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2181 spin_lock_irq(&emu->emu_lock);
2182 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002183 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185
2186 return 0;
2187}
2188
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002189static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190{
2191 return 0;
2192}
2193
2194static void copy_string(char *dst, char *src, char *null, int idx)
2195{
2196 if (src == NULL)
2197 sprintf(dst, "%s %02X", null, idx);
2198 else
2199 strcpy(dst, src);
2200}
2201
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002202static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2203 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
2205 char **fxbus, **extin, **extout;
2206 unsigned short fxbus_mask, extin_mask, extout_mask;
2207 int res;
2208
2209 memset(info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 info->internal_tram_size = emu->fx8010.itram_size;
2211 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2212 fxbus = fxbuses;
2213 extin = emu->audigy ? audigy_ins : creative_ins;
2214 extout = emu->audigy ? audigy_outs : creative_outs;
2215 fxbus_mask = emu->fx8010.fxbus_mask;
2216 extin_mask = emu->fx8010.extin_mask;
2217 extout_mask = emu->fx8010.extout_mask;
2218 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2219 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2220 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2221 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2222 }
2223 for (res = 16; res < 32; res++, extout++)
2224 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2225 info->gpr_controls = emu->fx8010.gpr_count;
2226 return 0;
2227}
2228
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002229static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002231 struct snd_emu10k1 *emu = hw->private_data;
2232 struct snd_emu10k1_fx8010_info *info;
2233 struct snd_emu10k1_fx8010_code *icode;
2234 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 unsigned int addr;
2236 void __user *argp = (void __user *)arg;
2237 int res;
2238
2239 switch (cmd) {
2240 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002241 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (!info)
2243 return -ENOMEM;
2244 if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
2245 kfree(info);
2246 return res;
2247 }
2248 if (copy_to_user(argp, info, sizeof(*info))) {
2249 kfree(info);
2250 return -EFAULT;
2251 }
2252 kfree(info);
2253 return 0;
2254 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2255 if (!capable(CAP_SYS_ADMIN))
2256 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002257 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 if (icode == NULL)
2259 return -ENOMEM;
2260 if (copy_from_user(icode, argp, sizeof(*icode))) {
2261 kfree(icode);
2262 return -EFAULT;
2263 }
2264 res = snd_emu10k1_icode_poke(emu, icode);
2265 kfree(icode);
2266 return res;
2267 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002268 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 if (icode == NULL)
2270 return -ENOMEM;
2271 if (copy_from_user(icode, argp, sizeof(*icode))) {
2272 kfree(icode);
2273 return -EFAULT;
2274 }
2275 res = snd_emu10k1_icode_peek(emu, icode);
2276 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2277 kfree(icode);
2278 return -EFAULT;
2279 }
2280 kfree(icode);
2281 return res;
2282 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002283 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 if (ipcm == NULL)
2285 return -ENOMEM;
2286 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2287 kfree(ipcm);
2288 return -EFAULT;
2289 }
2290 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2291 kfree(ipcm);
2292 return res;
2293 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002294 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 if (ipcm == NULL)
2296 return -ENOMEM;
2297 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2298 kfree(ipcm);
2299 return -EFAULT;
2300 }
2301 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2302 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2303 kfree(ipcm);
2304 return -EFAULT;
2305 }
2306 kfree(ipcm);
2307 return res;
2308 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2309 if (!capable(CAP_SYS_ADMIN))
2310 return -EPERM;
2311 if (get_user(addr, (unsigned int __user *)argp))
2312 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002313 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002315 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 return res;
2317 case SNDRV_EMU10K1_IOCTL_STOP:
2318 if (!capable(CAP_SYS_ADMIN))
2319 return -EPERM;
2320 if (emu->audigy)
2321 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2322 else
2323 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2324 return 0;
2325 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2326 if (!capable(CAP_SYS_ADMIN))
2327 return -EPERM;
2328 if (emu->audigy)
2329 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2330 else
2331 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2332 return 0;
2333 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2334 if (!capable(CAP_SYS_ADMIN))
2335 return -EPERM;
2336 if (emu->audigy)
2337 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2338 else
2339 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2340 udelay(10);
2341 if (emu->audigy)
2342 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2343 else
2344 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2345 return 0;
2346 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2347 if (!capable(CAP_SYS_ADMIN))
2348 return -EPERM;
2349 if (get_user(addr, (unsigned int __user *)argp))
2350 return -EFAULT;
2351 if (addr > 0x1ff)
2352 return -EINVAL;
2353 if (emu->audigy)
2354 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2355 else
2356 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2357 udelay(10);
2358 if (emu->audigy)
2359 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2360 else
2361 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2362 return 0;
2363 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2364 if (emu->audigy)
2365 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2366 else
2367 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2368 if (put_user(addr, (unsigned int __user *)argp))
2369 return -EFAULT;
2370 return 0;
2371 }
2372 return -ENOTTY;
2373}
2374
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002375static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376{
2377 return 0;
2378}
2379
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002380int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002382 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 int err;
2384
2385 if (rhwdep)
2386 *rhwdep = NULL;
2387 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2388 return err;
2389 strcpy(hw->name, "EMU10K1 (FX8010)");
2390 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2391 hw->ops.open = snd_emu10k1_fx8010_open;
2392 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2393 hw->ops.release = snd_emu10k1_fx8010_release;
2394 hw->private_data = emu;
2395 if (rhwdep)
2396 *rhwdep = hw;
2397 return 0;
2398}
Takashi Iwai09668b42005-11-17 16:14:10 +01002399
2400#ifdef CONFIG_PM
2401int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2402{
2403 int len;
2404
2405 len = emu->audigy ? 0x200 : 0x100;
2406 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2407 if (! emu->saved_gpr)
2408 return -ENOMEM;
2409 len = emu->audigy ? 0x100 : 0xa0;
2410 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2411 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2412 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2413 return -ENOMEM;
2414 len = emu->audigy ? 2 * 1024 : 2 * 512;
2415 emu->saved_icode = vmalloc(len * 4);
2416 if (! emu->saved_icode)
2417 return -ENOMEM;
2418 return 0;
2419}
2420
2421void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2422{
2423 kfree(emu->saved_gpr);
2424 kfree(emu->tram_val_saved);
2425 kfree(emu->tram_addr_saved);
2426 vfree(emu->saved_icode);
2427}
2428
2429/*
2430 * save/restore GPR, TRAM and codes
2431 */
2432void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2433{
2434 int i, len;
2435
2436 len = emu->audigy ? 0x200 : 0x100;
2437 for (i = 0; i < len; i++)
2438 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2439
2440 len = emu->audigy ? 0x100 : 0xa0;
2441 for (i = 0; i < len; i++) {
2442 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2443 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2444 if (emu->audigy) {
2445 emu->tram_addr_saved[i] >>= 12;
2446 emu->tram_addr_saved[i] |=
2447 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2448 }
2449 }
2450
2451 len = emu->audigy ? 2 * 1024 : 2 * 512;
2452 for (i = 0; i < len; i++)
2453 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2454}
2455
2456void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2457{
2458 int i, len;
2459
2460 /* set up TRAM */
2461 if (emu->fx8010.etram_pages.bytes > 0) {
2462 unsigned size, size_reg = 0;
2463 size = emu->fx8010.etram_pages.bytes / 2;
2464 size = (size - 1) >> 13;
2465 while (size) {
2466 size >>= 1;
2467 size_reg++;
2468 }
2469 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2470 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2471 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2472 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2473 }
2474
2475 if (emu->audigy)
2476 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2477 else
2478 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2479
2480 len = emu->audigy ? 0x200 : 0x100;
2481 for (i = 0; i < len; i++)
2482 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2483
2484 len = emu->audigy ? 0x100 : 0xa0;
2485 for (i = 0; i < len; i++) {
2486 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2487 emu->tram_val_saved[i]);
2488 if (! emu->audigy)
2489 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2490 emu->tram_addr_saved[i]);
2491 else {
2492 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2493 emu->tram_addr_saved[i] << 12);
2494 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2495 emu->tram_addr_saved[i] >> 20);
2496 }
2497 }
2498
2499 len = emu->audigy ? 2 * 1024 : 2 * 512;
2500 for (i = 0; i < len; i++)
2501 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2502
2503 /* start FX processor when the DSP code is updated */
2504 if (emu->audigy)
2505 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2506 else
2507 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2508}
2509#endif