blob: 13cd6ce898115171b903283674c90425357b984d [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>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010038#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <sound/emu10k1.h>
40
41#if 0 /* for testing purposes - digital out -> capture */
42#define EMU10K1_CAPTURE_DIGITAL_OUT
43#endif
44#if 0 /* for testing purposes - set S/PDIF to AC3 output */
45#define EMU10K1_SET_AC3_IEC958
46#endif
47#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
48#define EMU10K1_CENTER_LFE_FROM_FRONT
49#endif
50
51/*
52 * Tables
53 */
54
55static char *fxbuses[16] = {
56 /* 0x00 */ "PCM Left",
57 /* 0x01 */ "PCM Right",
58 /* 0x02 */ "PCM Surround Left",
59 /* 0x03 */ "PCM Surround Right",
60 /* 0x04 */ "MIDI Left",
61 /* 0x05 */ "MIDI Right",
62 /* 0x06 */ "Center",
63 /* 0x07 */ "LFE",
64 /* 0x08 */ NULL,
65 /* 0x09 */ NULL,
66 /* 0x0a */ NULL,
67 /* 0x0b */ NULL,
68 /* 0x0c */ "MIDI Reverb",
69 /* 0x0d */ "MIDI Chorus",
70 /* 0x0e */ NULL,
71 /* 0x0f */ NULL
72};
73
74static char *creative_ins[16] = {
75 /* 0x00 */ "AC97 Left",
76 /* 0x01 */ "AC97 Right",
77 /* 0x02 */ "TTL IEC958 Left",
78 /* 0x03 */ "TTL IEC958 Right",
79 /* 0x04 */ "Zoom Video Left",
80 /* 0x05 */ "Zoom Video Right",
81 /* 0x06 */ "Optical IEC958 Left",
82 /* 0x07 */ "Optical IEC958 Right",
83 /* 0x08 */ "Line/Mic 1 Left",
84 /* 0x09 */ "Line/Mic 1 Right",
85 /* 0x0a */ "Coaxial IEC958 Left",
86 /* 0x0b */ "Coaxial IEC958 Right",
87 /* 0x0c */ "Line/Mic 2 Left",
88 /* 0x0d */ "Line/Mic 2 Right",
89 /* 0x0e */ NULL,
90 /* 0x0f */ NULL
91};
92
93static char *audigy_ins[16] = {
94 /* 0x00 */ "AC97 Left",
95 /* 0x01 */ "AC97 Right",
96 /* 0x02 */ "Audigy CD Left",
97 /* 0x03 */ "Audigy CD Right",
98 /* 0x04 */ "Optical IEC958 Left",
99 /* 0x05 */ "Optical IEC958 Right",
100 /* 0x06 */ NULL,
101 /* 0x07 */ NULL,
102 /* 0x08 */ "Line/Mic 2 Left",
103 /* 0x09 */ "Line/Mic 2 Right",
104 /* 0x0a */ "SPDIF Left",
105 /* 0x0b */ "SPDIF Right",
106 /* 0x0c */ "Aux2 Left",
107 /* 0x0d */ "Aux2 Right",
108 /* 0x0e */ NULL,
109 /* 0x0f */ NULL
110};
111
112static char *creative_outs[32] = {
113 /* 0x00 */ "AC97 Left",
114 /* 0x01 */ "AC97 Right",
115 /* 0x02 */ "Optical IEC958 Left",
116 /* 0x03 */ "Optical IEC958 Right",
117 /* 0x04 */ "Center",
118 /* 0x05 */ "LFE",
119 /* 0x06 */ "Headphone Left",
120 /* 0x07 */ "Headphone Right",
121 /* 0x08 */ "Surround Left",
122 /* 0x09 */ "Surround Right",
123 /* 0x0a */ "PCM Capture Left",
124 /* 0x0b */ "PCM Capture Right",
125 /* 0x0c */ "MIC Capture",
126 /* 0x0d */ "AC97 Surround Left",
127 /* 0x0e */ "AC97 Surround Right",
128 /* 0x0f */ NULL,
129 /* 0x10 */ NULL,
130 /* 0x11 */ "Analog Center",
131 /* 0x12 */ "Analog LFE",
132 /* 0x13 */ NULL,
133 /* 0x14 */ NULL,
134 /* 0x15 */ NULL,
135 /* 0x16 */ NULL,
136 /* 0x17 */ NULL,
137 /* 0x18 */ NULL,
138 /* 0x19 */ NULL,
139 /* 0x1a */ NULL,
140 /* 0x1b */ NULL,
141 /* 0x1c */ NULL,
142 /* 0x1d */ NULL,
143 /* 0x1e */ NULL,
144 /* 0x1f */ NULL,
145};
146
147static char *audigy_outs[32] = {
148 /* 0x00 */ "Digital Front Left",
149 /* 0x01 */ "Digital Front Right",
150 /* 0x02 */ "Digital Center",
151 /* 0x03 */ "Digital LEF",
152 /* 0x04 */ "Headphone Left",
153 /* 0x05 */ "Headphone Right",
154 /* 0x06 */ "Digital Rear Left",
155 /* 0x07 */ "Digital Rear Right",
156 /* 0x08 */ "Front Left",
157 /* 0x09 */ "Front Right",
158 /* 0x0a */ "Center",
159 /* 0x0b */ "LFE",
160 /* 0x0c */ NULL,
161 /* 0x0d */ NULL,
162 /* 0x0e */ "Rear Left",
163 /* 0x0f */ "Rear Right",
164 /* 0x10 */ "AC97 Front Left",
165 /* 0x11 */ "AC97 Front Right",
166 /* 0x12 */ "ADC Caputre Left",
167 /* 0x13 */ "ADC Capture Right",
168 /* 0x14 */ NULL,
169 /* 0x15 */ NULL,
170 /* 0x16 */ NULL,
171 /* 0x17 */ NULL,
172 /* 0x18 */ NULL,
173 /* 0x19 */ NULL,
174 /* 0x1a */ NULL,
175 /* 0x1b */ NULL,
176 /* 0x1c */ NULL,
177 /* 0x1d */ NULL,
178 /* 0x1e */ NULL,
179 /* 0x1f */ NULL,
180};
181
182static const u32 bass_table[41][5] = {
183 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
184 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
185 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
186 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
187 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
188 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
189 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
190 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
191 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
192 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
193 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
194 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
195 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
196 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
197 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
198 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
199 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
200 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
201 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
202 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
203 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
204 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
205 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
206 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
207 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
208 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
209 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
210 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
211 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
212 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
213 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
214 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
215 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
216 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
217 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
218 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
219 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
220 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
221 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
222 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
223 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
224};
225
226static const u32 treble_table[41][5] = {
227 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
228 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
229 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
230 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
231 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
232 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
233 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
234 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
235 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
236 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
237 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
238 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
239 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
240 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
241 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
242 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
243 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
244 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
245 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
246 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
247 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
248 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
249 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
250 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
251 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
252 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
253 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
254 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
255 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
256 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
257 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
258 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
259 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
260 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
261 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
262 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
263 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
264 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
265 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
266 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
267 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
268};
269
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100270/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271static const u32 db_table[101] = {
272 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
273 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
274 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
275 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
276 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
277 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
278 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
279 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
280 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
281 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
282 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
283 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
284 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
285 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
286 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
287 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
288 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
289 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
290 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
291 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
292 0x7fffffff,
293};
294
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100295/* EMU10k1/EMU10k2 DSP control db gain */
296static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298static const u32 onoff_table[2] = {
299 0x00000000, 0x00000001
300};
301
302/*
303 */
304
305static inline mm_segment_t snd_enter_user(void)
306{
307 mm_segment_t fs = get_fs();
308 set_fs(get_ds());
309 return fs;
310}
311
312static inline void snd_leave_user(mm_segment_t fs)
313{
314 set_fs(fs);
315}
316
317/*
318 * controls
319 */
320
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100321static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100323 struct snd_emu10k1_fx8010_ctl *ctl =
324 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 if (ctl->min == 0 && ctl->max == 1)
327 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
328 else
329 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
330 uinfo->count = ctl->vcount;
331 uinfo->value.integer.min = ctl->min;
332 uinfo->value.integer.max = ctl->max;
333 return 0;
334}
335
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100336static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100338 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
339 struct snd_emu10k1_fx8010_ctl *ctl =
340 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 unsigned long flags;
342 unsigned int i;
343
344 spin_lock_irqsave(&emu->reg_lock, flags);
345 for (i = 0; i < ctl->vcount; i++)
346 ucontrol->value.integer.value[i] = ctl->value[i];
347 spin_unlock_irqrestore(&emu->reg_lock, flags);
348 return 0;
349}
350
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100351static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100353 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
354 struct snd_emu10k1_fx8010_ctl *ctl =
355 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 unsigned long flags;
357 unsigned int nval, val;
358 unsigned int i, j;
359 int change = 0;
360
361 spin_lock_irqsave(&emu->reg_lock, flags);
362 for (i = 0; i < ctl->vcount; i++) {
363 nval = ucontrol->value.integer.value[i];
364 if (nval < ctl->min)
365 nval = ctl->min;
366 if (nval > ctl->max)
367 nval = ctl->max;
368 if (nval != ctl->value[i])
369 change = 1;
370 val = ctl->value[i] = nval;
371 switch (ctl->translation) {
372 case EMU10K1_GPR_TRANSLATION_NONE:
373 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
374 break;
375 case EMU10K1_GPR_TRANSLATION_TABLE100:
376 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
377 break;
378 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200379 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
380 change = -EIO;
381 goto __error;
382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 for (j = 0; j < 5; j++)
384 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
385 break;
386 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200387 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
388 change = -EIO;
389 goto __error;
390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 for (j = 0; j < 5; j++)
392 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
393 break;
394 case EMU10K1_GPR_TRANSLATION_ONOFF:
395 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
396 break;
397 }
398 }
399 __error:
400 spin_unlock_irqrestore(&emu->reg_lock, flags);
401 return change;
402}
403
404/*
405 * Interrupt handler
406 */
407
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100408static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100410 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 irq = emu->fx8010.irq_handlers;
413 while (irq) {
414 nirq = irq->next; /* irq ptr can be removed from list */
415 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
416 if (irq->handler)
417 irq->handler(emu, irq->private_data);
418 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
419 }
420 irq = nirq;
421 }
422}
423
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100424int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
425 snd_fx8010_irq_handler_t *handler,
426 unsigned char gpr_running,
427 void *private_data,
428 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100430 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 unsigned long flags;
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
434 if (irq == NULL)
435 return -ENOMEM;
436 irq->handler = handler;
437 irq->gpr_running = gpr_running;
438 irq->private_data = private_data;
439 irq->next = NULL;
440 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
441 if (emu->fx8010.irq_handlers == NULL) {
442 emu->fx8010.irq_handlers = irq;
443 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
444 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
445 } else {
446 irq->next = emu->fx8010.irq_handlers;
447 emu->fx8010.irq_handlers = irq;
448 }
449 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
450 if (r_irq)
451 *r_irq = irq;
452 return 0;
453}
454
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100455int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
456 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100458 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 unsigned long flags;
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
462 if ((tmp = emu->fx8010.irq_handlers) == irq) {
463 emu->fx8010.irq_handlers = tmp->next;
464 if (emu->fx8010.irq_handlers == NULL) {
465 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
466 emu->dsp_interrupt = NULL;
467 }
468 } else {
469 while (tmp && tmp->next != irq)
470 tmp = tmp->next;
471 if (tmp)
472 tmp->next = tmp->next->next;
473 }
474 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
475 kfree(irq);
476 return 0;
477}
478
479/*************************************************************************
480 * EMU10K1 effect manager
481 *************************************************************************/
482
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100483static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
484 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 u32 op, u32 r, u32 a, u32 x, u32 y)
486{
487 u_int32_t *code;
488 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200489 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 set_bit(*ptr, icode->code_valid);
491 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
492 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
493 (*ptr)++;
494}
495
496#define OP(icode, ptr, op, r, a, x, y) \
497 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
498
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100499static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
500 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 u32 op, u32 r, u32 a, u32 x, u32 y)
502{
503 u_int32_t *code;
504 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200505 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 set_bit(*ptr, icode->code_valid);
507 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
508 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
509 (*ptr)++;
510}
511
512#define A_OP(icode, ptr, op, r, a, x, y) \
513 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
514
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100515static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
518 snd_emu10k1_ptr_write(emu, pc, 0, data);
519}
520
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100521unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
523 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
524 return snd_emu10k1_ptr_read(emu, pc, 0);
525}
526
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100527static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
528 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529{
530 int gpr;
531 u32 val;
532
533 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
534 if (!test_bit(gpr, icode->gpr_valid))
535 continue;
536 if (get_user(val, &icode->gpr_map[gpr]))
537 return -EFAULT;
538 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
539 }
540 return 0;
541}
542
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100543static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
544 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
546 int gpr;
547 u32 val;
548
549 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
550 set_bit(gpr, icode->gpr_valid);
551 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
552 if (put_user(val, &icode->gpr_map[gpr]))
553 return -EFAULT;
554 }
555 return 0;
556}
557
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100558static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
559 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
561 int tram;
562 u32 addr, val;
563
564 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
565 if (!test_bit(tram, icode->tram_valid))
566 continue;
567 if (get_user(val, &icode->tram_data_map[tram]) ||
568 get_user(addr, &icode->tram_addr_map[tram]))
569 return -EFAULT;
570 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
571 if (!emu->audigy) {
572 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
573 } else {
574 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
575 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
576 }
577 }
578 return 0;
579}
580
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100581static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
582 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 int tram;
585 u32 val, addr;
586
587 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
588 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
589 set_bit(tram, icode->tram_valid);
590 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
591 if (!emu->audigy) {
592 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
593 } else {
594 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
595 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
596 }
597 if (put_user(val, &icode->tram_data_map[tram]) ||
598 put_user(addr, &icode->tram_addr_map[tram]))
599 return -EFAULT;
600 }
601 return 0;
602}
603
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100604static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
605 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
607 u32 pc, lo, hi;
608
609 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
610 if (!test_bit(pc / 2, icode->code_valid))
611 continue;
612 if (get_user(lo, &icode->code[pc + 0]) ||
613 get_user(hi, &icode->code[pc + 1]))
614 return -EFAULT;
615 snd_emu10k1_efx_write(emu, pc + 0, lo);
616 snd_emu10k1_efx_write(emu, pc + 1, hi);
617 }
618 return 0;
619}
620
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100621static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
622 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
624 u32 pc;
625
626 memset(icode->code_valid, 0, sizeof(icode->code_valid));
627 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
628 set_bit(pc / 2, icode->code_valid);
629 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
630 return -EFAULT;
631 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
632 return -EFAULT;
633 }
634 return 0;
635}
636
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100637static struct snd_emu10k1_fx8010_ctl *
638snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100640 struct snd_emu10k1_fx8010_ctl *ctl;
641 struct snd_kcontrol *kcontrol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 struct list_head *list;
643
644 list_for_each(list, &emu->fx8010.gpr_ctl) {
645 ctl = emu10k1_gpr_ctl(list);
646 kcontrol = ctl->kcontrol;
647 if (kcontrol->id.iface == id->iface &&
648 !strcmp(kcontrol->id.name, id->name) &&
649 kcontrol->id.index == id->index)
650 return ctl;
651 }
652 return NULL;
653}
654
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100655static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
656 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100659 struct snd_ctl_elem_id __user *_id;
660 struct snd_ctl_elem_id id;
661 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
662 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 int err;
664
665 for (i = 0, _id = icode->gpr_del_controls;
666 i < icode->gpr_del_control_count; i++, _id++) {
667 if (copy_from_user(&id, _id, sizeof(id)))
668 return -EFAULT;
669 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
670 return -ENOENT;
671 }
672 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
673 if (! gctl)
674 return -ENOMEM;
675 err = 0;
676 for (i = 0, _gctl = icode->gpr_add_controls;
677 i < icode->gpr_add_control_count; i++, _gctl++) {
678 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
679 err = -EFAULT;
680 goto __error;
681 }
682 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
683 continue;
684 down_read(&emu->card->controls_rwsem);
685 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
686 up_read(&emu->card->controls_rwsem);
687 err = -EEXIST;
688 goto __error;
689 }
690 up_read(&emu->card->controls_rwsem);
691 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
692 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
693 err = -EINVAL;
694 goto __error;
695 }
696 }
697 for (i = 0, _gctl = icode->gpr_list_controls;
698 i < icode->gpr_list_control_count; i++, _gctl++) {
699 /* FIXME: we need to check the WRITE access */
700 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
701 err = -EFAULT;
702 goto __error;
703 }
704 }
705 __error:
706 kfree(gctl);
707 return err;
708}
709
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100710static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100712 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100714 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 kctl->private_value = 0;
716 list_del(&ctl->list);
717 kfree(ctl);
718}
719
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100720static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
721 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
723 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100724 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
725 struct snd_emu10k1_fx8010_control_gpr *gctl;
726 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
727 struct snd_kcontrol_new knew;
728 struct snd_kcontrol *kctl;
729 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 int err = 0;
731
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100732 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
734 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
735 if (!val || !gctl || !nctl) {
736 err = -ENOMEM;
737 goto __error;
738 }
739
740 for (i = 0, _gctl = icode->gpr_add_controls;
741 i < icode->gpr_add_control_count; i++, _gctl++) {
742 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
743 err = -EFAULT;
744 goto __error;
745 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200746 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
747 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
748 err = -EINVAL;
749 goto __error;
750 }
751 if (! gctl->id.name[0]) {
752 err = -EINVAL;
753 goto __error;
754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
756 memset(&knew, 0, sizeof(knew));
757 knew.iface = gctl->id.iface;
758 knew.name = gctl->id.name;
759 knew.index = gctl->id.index;
760 knew.device = gctl->id.device;
761 knew.subdevice = gctl->id.subdevice;
762 knew.info = snd_emu10k1_gpr_ctl_info;
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100763 if (gctl->tlv.p) {
764 knew.tlv.p = gctl->tlv.p;
765 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
766 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 knew.get = snd_emu10k1_gpr_ctl_get;
769 knew.put = snd_emu10k1_gpr_ctl_put;
770 memset(nctl, 0, sizeof(*nctl));
771 nctl->vcount = gctl->vcount;
772 nctl->count = gctl->count;
773 for (j = 0; j < 32; j++) {
774 nctl->gpr[j] = gctl->gpr[j];
775 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
776 val->value.integer.value[j] = gctl->value[j];
777 }
778 nctl->min = gctl->min;
779 nctl->max = gctl->max;
780 nctl->translation = gctl->translation;
781 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100782 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (ctl == NULL) {
784 err = -ENOMEM;
785 goto __error;
786 }
787 knew.private_value = (unsigned long)ctl;
788 *ctl = *nctl;
789 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
790 kfree(ctl);
791 goto __error;
792 }
793 kctl->private_free = snd_emu10k1_ctl_private_free;
794 ctl->kcontrol = kctl;
795 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
796 } else {
797 /* overwrite */
798 nctl->list = ctl->list;
799 nctl->kcontrol = ctl->kcontrol;
800 *ctl = *nctl;
801 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
802 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
803 }
804 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
805 }
806 __error:
807 kfree(nctl);
808 kfree(gctl);
809 kfree(val);
810 return err;
811}
812
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100813static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
814 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100817 struct snd_ctl_elem_id id;
818 struct snd_ctl_elem_id __user *_id;
819 struct snd_emu10k1_fx8010_ctl *ctl;
820 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 for (i = 0, _id = icode->gpr_del_controls;
823 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200824 if (copy_from_user(&id, _id, sizeof(id)))
825 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 down_write(&card->controls_rwsem);
827 ctl = snd_emu10k1_look_for_ctl(emu, &id);
828 if (ctl)
829 snd_ctl_remove(card, ctl->kcontrol);
830 up_write(&card->controls_rwsem);
831 }
832 return 0;
833}
834
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100835static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
836 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837{
838 unsigned int i = 0, j;
839 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100840 struct snd_emu10k1_fx8010_control_gpr *gctl;
841 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
842 struct snd_emu10k1_fx8010_ctl *ctl;
843 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 struct list_head *list;
845
846 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
847 if (! gctl)
848 return -ENOMEM;
849
850 _gctl = icode->gpr_list_controls;
851 list_for_each(list, &emu->fx8010.gpr_ctl) {
852 ctl = emu10k1_gpr_ctl(list);
853 total++;
854 if (_gctl && i < icode->gpr_list_control_count) {
855 memset(gctl, 0, sizeof(*gctl));
856 id = &ctl->kcontrol->id;
857 gctl->id.iface = id->iface;
858 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
859 gctl->id.index = id->index;
860 gctl->id.device = id->device;
861 gctl->id.subdevice = id->subdevice;
862 gctl->vcount = ctl->vcount;
863 gctl->count = ctl->count;
864 for (j = 0; j < 32; j++) {
865 gctl->gpr[j] = ctl->gpr[j];
866 gctl->value[j] = ctl->value[j];
867 }
868 gctl->min = ctl->min;
869 gctl->max = ctl->max;
870 gctl->translation = ctl->translation;
871 if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
872 kfree(gctl);
873 return -EFAULT;
874 }
875 _gctl++;
876 i++;
877 }
878 }
879 icode->gpr_list_control_total = total;
880 kfree(gctl);
881 return 0;
882}
883
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100884static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
885 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 int err = 0;
888
Ingo Molnar62932df2006-01-16 16:34:20 +0100889 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
891 goto __error;
892 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
893 /* stop FX processor - this may be dangerous, but it's better to miss
894 some samples than generate wrong ones - [jk] */
895 if (emu->audigy)
896 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
897 else
898 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
899 /* ok, do the main job */
900 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
901 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
902 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
903 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
904 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
905 goto __error;
906 /* start FX processor when the DSP code is updated */
907 if (emu->audigy)
908 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
909 else
910 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
911 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100912 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return err;
914}
915
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100916static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
917 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
919 int err;
920
Ingo Molnar62932df2006-01-16 16:34:20 +0100921 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
923 /* ok, do the main job */
924 err = snd_emu10k1_gpr_peek(emu, icode);
925 if (err >= 0)
926 err = snd_emu10k1_tram_peek(emu, icode);
927 if (err >= 0)
928 err = snd_emu10k1_code_peek(emu, icode);
929 if (err >= 0)
930 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100931 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return err;
933}
934
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100935static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
936 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 unsigned int i;
939 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100940 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
943 return -EINVAL;
944 if (ipcm->channels > 32)
945 return -EINVAL;
946 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100947 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 spin_lock_irq(&emu->reg_lock);
949 if (pcm->opened) {
950 err = -EBUSY;
951 goto __error;
952 }
953 if (ipcm->channels == 0) { /* remove */
954 pcm->valid = 0;
955 } else {
956 /* FIXME: we need to add universal code to the PCM transfer routine */
957 if (ipcm->channels != 2) {
958 err = -EINVAL;
959 goto __error;
960 }
961 pcm->valid = 1;
962 pcm->opened = 0;
963 pcm->channels = ipcm->channels;
964 pcm->tram_start = ipcm->tram_start;
965 pcm->buffer_size = ipcm->buffer_size;
966 pcm->gpr_size = ipcm->gpr_size;
967 pcm->gpr_count = ipcm->gpr_count;
968 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
969 pcm->gpr_ptr = ipcm->gpr_ptr;
970 pcm->gpr_trigger = ipcm->gpr_trigger;
971 pcm->gpr_running = ipcm->gpr_running;
972 for (i = 0; i < pcm->channels; i++)
973 pcm->etram[i] = ipcm->etram[i];
974 }
975 __error:
976 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +0100977 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return err;
979}
980
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100981static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
982 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983{
984 unsigned int i;
985 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100986 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
989 return -EINVAL;
990 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100991 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 spin_lock_irq(&emu->reg_lock);
993 ipcm->channels = pcm->channels;
994 ipcm->tram_start = pcm->tram_start;
995 ipcm->buffer_size = pcm->buffer_size;
996 ipcm->gpr_size = pcm->gpr_size;
997 ipcm->gpr_ptr = pcm->gpr_ptr;
998 ipcm->gpr_count = pcm->gpr_count;
999 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1000 ipcm->gpr_trigger = pcm->gpr_trigger;
1001 ipcm->gpr_running = pcm->gpr_running;
1002 for (i = 0; i < pcm->channels; i++)
1003 ipcm->etram[i] = pcm->etram[i];
1004 ipcm->res1 = ipcm->res2 = 0;
1005 ipcm->pad = 0;
1006 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001007 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return err;
1009}
1010
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001011#define SND_EMU10K1_GPR_CONTROLS 44
1012#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1014#define SND_EMU10K1_CAPTURE_CHANNELS 4
1015
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001016static void __devinit
1017snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1018 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019{
1020 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1021 strcpy(ctl->id.name, name);
1022 ctl->vcount = ctl->count = 1;
1023 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1024 ctl->min = 0;
1025 ctl->max = 100;
James Courtier-Dutton31508f82006-07-22 17:02:10 +01001026 ctl->tlv.p = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1028}
1029
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001030static void __devinit
1031snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1032 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
1034 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1035 strcpy(ctl->id.name, name);
1036 ctl->vcount = ctl->count = 2;
1037 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1038 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1039 ctl->min = 0;
1040 ctl->max = 100;
James Courtier-Dutton31508f82006-07-22 17:02:10 +01001041 ctl->tlv.p = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1043}
1044
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001045static void __devinit
1046snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1047 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048{
1049 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1050 strcpy(ctl->id.name, name);
1051 ctl->vcount = ctl->count = 1;
1052 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1053 ctl->min = 0;
1054 ctl->max = 1;
1055 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1056}
1057
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001058static void __devinit
1059snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1060 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061{
1062 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1063 strcpy(ctl->id.name, name);
1064 ctl->vcount = ctl->count = 2;
1065 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1066 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1067 ctl->min = 0;
1068 ctl->max = 1;
1069 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1070}
1071
1072
1073/*
1074 * initial DSP configuration for Audigy
1075 */
1076
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001077static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
1079 int err, i, z, gpr, nctl;
1080 const int playback = 10;
1081 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1082 const int stereo_mix = capture + 2;
1083 const int tmp = 0x88;
1084 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001085 struct snd_emu10k1_fx8010_code *icode = NULL;
1086 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 u32 *gpr_map;
1088 mm_segment_t seg;
1089
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001090 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001091 (icode->gpr_map = (u_int32_t __user *)
1092 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1093 GFP_KERNEL)) == NULL ||
1094 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1095 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 err = -ENOMEM;
1097 goto __err;
1098 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001099 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 icode->tram_data_map = icode->gpr_map + 512;
1102 icode->tram_addr_map = icode->tram_data_map + 256;
1103 icode->code = icode->tram_addr_map + 256;
1104
1105 /* clear free GPRs */
1106 for (i = 0; i < 512; i++)
1107 set_bit(i, icode->gpr_valid);
1108
1109 /* clear TRAM data & address lines */
1110 for (i = 0; i < 256; i++)
1111 set_bit(i, icode->tram_valid);
1112
1113 strcpy(icode->name, "Audigy DSP code for ALSA");
1114 ptr = 0;
1115 nctl = 0;
1116 gpr = stereo_mix + 10;
1117
1118 /* stop FX processor */
1119 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1120
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001121#if 0
1122 /* FIX: jcd test */
1123 for (z = 0; z < 80; z=z+2) {
1124 A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
1125 A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
1126 }
1127#endif /* jcd test */
1128#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 /* PCM front Playback Volume (independent from stereo mix) */
1130 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1131 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1132 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1133 gpr += 2;
1134
1135 /* PCM Surround Playback (independent from stereo mix) */
1136 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1137 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1138 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1139 gpr += 2;
1140
1141 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001142 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1144 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1145 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1146 gpr += 2;
1147 }
1148
1149 /* PCM Center Playback (independent from stereo mix) */
1150 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1151 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1152 gpr++;
1153
1154 /* PCM LFE Playback (independent from stereo mix) */
1155 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1156 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1157 gpr++;
1158
1159 /*
1160 * Stereo Mix
1161 */
1162 /* Wave (PCM) Playback Volume (will be renamed later) */
1163 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1164 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1165 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1166 gpr += 2;
1167
1168 /* Synth Playback */
1169 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1170 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1171 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1172 gpr += 2;
1173
1174 /* Wave (PCM) Capture */
1175 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1176 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1177 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1178 gpr += 2;
1179
1180 /* Synth Capture */
1181 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1182 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1183 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1184 gpr += 2;
1185
1186 /*
1187 * inputs
1188 */
1189#define A_ADD_VOLUME_IN(var,vol,input) \
1190A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1191
1192 /* AC'97 Playback Volume - used only for mic (renamed later) */
1193 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1194 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1195 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1196 gpr += 2;
1197 /* AC'97 Capture Volume - used only for mic */
1198 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1199 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1200 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1201 gpr += 2;
1202
1203 /* mic capture buffer */
1204 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1205
1206 /* Audigy CD Playback Volume */
1207 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1208 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1209 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001210 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 gpr, 0);
1212 gpr += 2;
1213 /* Audigy CD Capture Volume */
1214 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1215 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1216 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001217 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 gpr, 0);
1219 gpr += 2;
1220
1221 /* Optical SPDIF Playback Volume */
1222 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1223 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001224 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 gpr += 2;
1226 /* Optical SPDIF Capture Volume */
1227 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1228 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001229 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 gpr += 2;
1231
1232 /* Line2 Playback Volume */
1233 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1234 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1235 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001236 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 gpr, 0);
1238 gpr += 2;
1239 /* Line2 Capture Volume */
1240 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1241 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1242 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001243 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 gpr, 0);
1245 gpr += 2;
1246
1247 /* Philips ADC Playback Volume */
1248 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1249 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1250 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1251 gpr += 2;
1252 /* Philips ADC Capture Volume */
1253 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1254 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1255 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1256 gpr += 2;
1257
1258 /* Aux2 Playback Volume */
1259 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1260 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1261 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001262 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 gpr, 0);
1264 gpr += 2;
1265 /* Aux2 Capture Volume */
1266 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1267 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1268 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001269 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 gpr, 0);
1271 gpr += 2;
1272
1273 /* Stereo Mix Front Playback Volume */
1274 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1275 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1276 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1277 gpr += 2;
1278
1279 /* Stereo Mix Surround Playback */
1280 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1281 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1282 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1283 gpr += 2;
1284
1285 /* Stereo Mix Center Playback */
1286 /* Center = sub = Left/2 + Right/2 */
1287 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1288 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1289 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1290 gpr++;
1291
1292 /* Stereo Mix LFE Playback */
1293 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1294 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1295 gpr++;
1296
Lee Revell2b637da2005-03-30 13:51:18 +02001297 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 /* Stereo Mix Side Playback */
1299 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1300 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1301 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1302 gpr += 2;
1303 }
1304
1305 /*
1306 * outputs
1307 */
1308#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1309#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1310 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1311
1312#define _A_SWITCH(icode, ptr, dst, src, sw) \
1313 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1314#define A_SWITCH(icode, ptr, dst, src, sw) \
1315 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1316#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1317 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1318#define A_SWITCH_NEG(icode, ptr, dst, src) \
1319 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1320
1321
1322 /*
1323 * Process tone control
1324 */
1325 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1326 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1327 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 */
1328 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 */
1329 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1330 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 +02001331 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 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 */
1333 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 */
1334 }
1335
1336
1337 ctl = &controls[nctl + 0];
1338 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1339 strcpy(ctl->id.name, "Tone Control - Bass");
1340 ctl->vcount = 2;
1341 ctl->count = 10;
1342 ctl->min = 0;
1343 ctl->max = 40;
1344 ctl->value[0] = ctl->value[1] = 20;
1345 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1346 ctl = &controls[nctl + 1];
1347 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1348 strcpy(ctl->id.name, "Tone Control - Treble");
1349 ctl->vcount = 2;
1350 ctl->count = 10;
1351 ctl->min = 0;
1352 ctl->max = 40;
1353 ctl->value[0] = ctl->value[1] = 20;
1354 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1355
1356#define BASS_GPR 0x8c
1357#define TREBLE_GPR 0x96
1358
1359 for (z = 0; z < 5; z++) {
1360 int j;
1361 for (j = 0; j < 2; j++) {
1362 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1363 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1364 }
1365 }
1366 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1367 int j, k, l, d;
1368 for (j = 0; j < 2; j++) { /* left/right */
1369 k = 0xb0 + (z * 8) + (j * 4);
1370 l = 0xe0 + (z * 8) + (j * 4);
1371 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1372
1373 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1374 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1375 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1376 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1377 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1378 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1379
1380 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1381 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1382 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1383 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1384 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1385 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1386
1387 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1388
1389 if (z == 2) /* center */
1390 break;
1391 }
1392 }
1393 nctl += 2;
1394
1395#undef BASS_GPR
1396#undef TREBLE_GPR
1397
1398 for (z = 0; z < 8; z++) {
1399 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1400 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1401 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1402 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1403 }
1404 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1405 gpr += 2;
1406
1407 /* Master volume (will be renamed later) */
1408 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));
1409 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));
1410 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));
1411 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));
1412 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));
1413 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));
1414 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));
1415 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));
1416 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1417 gpr += 2;
1418
1419 /* analog speakers */
1420 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1421 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1422 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1423 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001424 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1426
1427 /* headphone */
1428 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1429
1430 /* digital outputs */
1431 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
1432
1433 /* IEC958 Optical Raw Playback Switch */
1434 gpr_map[gpr++] = 0;
1435 gpr_map[gpr++] = 0x1008;
1436 gpr_map[gpr++] = 0xffff0000;
1437 for (z = 0; z < 2; z++) {
1438 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1439 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1440 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1441 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1442 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1443 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1444 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1445 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1446 /* 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 +02001447 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1449 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1450 } else {
1451 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1452 }
1453 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001454 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 -07001455 gpr += 2;
1456
1457 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1458 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1459 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1460
1461 /* ADC buffer */
1462#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1463 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1464#else
1465 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1466 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1467#endif
1468
1469 /* EFX capture - capture the 16 EXTINs */
1470 for (z = 0; z < 16; z++) {
1471 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1472 }
1473
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001474#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 /*
1476 * ok, set up done..
1477 */
1478
1479 if (gpr > tmp) {
1480 snd_BUG();
1481 err = -EIO;
1482 goto __err;
1483 }
1484 /* clear remaining instruction memory */
1485 while (ptr < 0x400)
1486 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1487
1488 seg = snd_enter_user();
1489 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001490 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 err = snd_emu10k1_icode_poke(emu, icode);
1492 snd_leave_user(seg);
1493
1494 __err:
1495 kfree(controls);
1496 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001497 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 kfree(icode);
1499 }
1500 return err;
1501}
1502
1503
1504/*
1505 * initial DSP configuration for Emu10k1
1506 */
1507
1508/* when volume = max, then copy only to avoid volume modification */
1509/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001510static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1513 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1514 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1515 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1516}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001517static 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 -07001518{
1519 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1520 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1521 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1522 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1523 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1524}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001525static 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 -07001526{
1527 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1528 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1529 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1530 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1531 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1532}
1533
1534#define VOLUME(icode, ptr, dst, src, vol) \
1535 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1536#define VOLUME_IN(icode, ptr, dst, src, vol) \
1537 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1538#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1539 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1540#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1541 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1542#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1543 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1544#define _SWITCH(icode, ptr, dst, src, sw) \
1545 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1546#define SWITCH(icode, ptr, dst, src, sw) \
1547 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1548#define SWITCH_IN(icode, ptr, dst, src, sw) \
1549 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1550#define _SWITCH_NEG(icode, ptr, dst, src) \
1551 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1552#define SWITCH_NEG(icode, ptr, dst, src) \
1553 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1554
1555
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001556static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557{
1558 int err, i, z, gpr, tmp, playback, capture;
1559 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001560 struct snd_emu10k1_fx8010_code *icode;
1561 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1562 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 u32 *gpr_map;
1564 mm_segment_t seg;
1565
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001566 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001568 if ((icode->gpr_map = (u_int32_t __user *)
1569 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1570 GFP_KERNEL)) == NULL ||
1571 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1572 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1573 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001574 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 err = -ENOMEM;
1576 goto __err;
1577 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001578 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580 icode->tram_data_map = icode->gpr_map + 256;
1581 icode->tram_addr_map = icode->tram_data_map + 160;
1582 icode->code = icode->tram_addr_map + 160;
1583
1584 /* clear free GPRs */
1585 for (i = 0; i < 256; i++)
1586 set_bit(i, icode->gpr_valid);
1587
1588 /* clear TRAM data & address lines */
1589 for (i = 0; i < 160; i++)
1590 set_bit(i, icode->tram_valid);
1591
1592 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1593 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001594 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 playback = SND_EMU10K1_INPUTS;
1596 /* we have 6 playback channels and tone control doubles */
1597 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1598 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1599 tmp = 0x88; /* we need 4 temporary GPR */
1600 /* from 0x8c to 0xff is the area for tone control */
1601
1602 /* stop FX processor */
1603 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1604
1605 /*
1606 * Process FX Buses
1607 */
1608 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1609 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1610 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1611 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1612 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1613 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1614 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1615 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1616 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1617 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001618 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1619 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
1621 /* Raw S/PDIF PCM */
1622 ipcm->substream = 0;
1623 ipcm->channels = 2;
1624 ipcm->tram_start = 0;
1625 ipcm->buffer_size = (64 * 1024) / 2;
1626 ipcm->gpr_size = gpr++;
1627 ipcm->gpr_ptr = gpr++;
1628 ipcm->gpr_count = gpr++;
1629 ipcm->gpr_tmpcount = gpr++;
1630 ipcm->gpr_trigger = gpr++;
1631 ipcm->gpr_running = gpr++;
1632 ipcm->etram[0] = 0;
1633 ipcm->etram[1] = 1;
1634
1635 gpr_map[gpr + 0] = 0xfffff000;
1636 gpr_map[gpr + 1] = 0xffff0000;
1637 gpr_map[gpr + 2] = 0x70000000;
1638 gpr_map[gpr + 3] = 0x00000007;
1639 gpr_map[gpr + 4] = 0x001f << 11;
1640 gpr_map[gpr + 5] = 0x001c << 11;
1641 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1642 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1643 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1644 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1645 gpr_map[gpr + 10] = 1<<11;
1646 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1647 gpr_map[gpr + 12] = 0;
1648
1649 /* if the trigger flag is not set, skip */
1650 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1651 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1652 /* if the running flag is set, we're running */
1653 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1654 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1655 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1656 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1657 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1658 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1659 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1660
1661 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1662 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1663 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1664 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1665
1666 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1667 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1668 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1669 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1670 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1671
1672 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1673 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1674 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1675 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1676 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1677
1678 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1679 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1680 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1681 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1682 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1683
1684 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1685 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1686 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1687 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1688 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1689
1690 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1691 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1692
1693 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1694 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1695
1696 /* 24: */
1697 gpr += 13;
1698
1699 /* Wave Playback Volume */
1700 for (z = 0; z < 2; z++)
1701 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1702 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1703 gpr += 2;
1704
1705 /* Wave Surround Playback Volume */
1706 for (z = 0; z < 2; z++)
1707 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1708 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1709 gpr += 2;
1710
1711 /* Wave Center/LFE Playback Volume */
1712 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1713 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1714 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1715 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1716 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1717 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1718
1719 /* Wave Capture Volume + Switch */
1720 for (z = 0; z < 2; z++) {
1721 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1722 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1723 }
1724 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1725 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1726 gpr += 4;
1727
1728 /* Synth Playback Volume */
1729 for (z = 0; z < 2; z++)
1730 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1731 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1732 gpr += 2;
1733
1734 /* Synth Capture Volume + Switch */
1735 for (z = 0; z < 2; z++) {
1736 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1737 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1738 }
1739 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1740 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1741 gpr += 4;
1742
1743 /* Surround Digital Playback Volume (renamed later without Digital) */
1744 for (z = 0; z < 2; z++)
1745 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1746 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1747 gpr += 2;
1748
1749 /* Surround Capture Volume + Switch */
1750 for (z = 0; z < 2; z++) {
1751 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1752 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1753 }
1754 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1755 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1756 gpr += 4;
1757
1758 /* Center Playback Volume (renamed later without Digital) */
1759 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1760 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1761
1762 /* LFE Playback Volume + Switch (renamed later without Digital) */
1763 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1764 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1765
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001766 /* Front Playback Volume */
1767 for (z = 0; z < 2; z++)
1768 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1769 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1770 gpr += 2;
1771
1772 /* Front Capture Volume + Switch */
1773 for (z = 0; z < 2; z++) {
1774 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1775 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1776 }
1777 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
1778 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
1779 gpr += 3;
1780
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 /*
1782 * Process inputs
1783 */
1784
1785 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
1786 /* AC'97 Playback Volume */
1787 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
1788 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
1789 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
1790 /* AC'97 Capture Volume */
1791 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
1792 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
1793 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
1794 }
1795
1796 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
1797 /* IEC958 TTL Playback Volume */
1798 for (z = 0; z < 2; z++)
1799 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001800 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 gpr += 2;
1802
1803 /* IEC958 TTL Capture Volume + Switch */
1804 for (z = 0; z < 2; z++) {
1805 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
1806 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1807 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001808 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
1809 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 -07001810 gpr += 4;
1811 }
1812
1813 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
1814 /* Zoom Video Playback Volume */
1815 for (z = 0; z < 2; z++)
1816 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
1817 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
1818 gpr += 2;
1819
1820 /* Zoom Video Capture Volume + Switch */
1821 for (z = 0; z < 2; z++) {
1822 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
1823 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1824 }
1825 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
1826 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
1827 gpr += 4;
1828 }
1829
1830 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
1831 /* IEC958 Optical Playback Volume */
1832 for (z = 0; z < 2; z++)
1833 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001834 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 gpr += 2;
1836
1837 /* IEC958 Optical Capture Volume */
1838 for (z = 0; z < 2; z++) {
1839 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
1840 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1841 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001842 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
1843 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 -07001844 gpr += 4;
1845 }
1846
1847 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
1848 /* Line LiveDrive Playback Volume */
1849 for (z = 0; z < 2; z++)
1850 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
1851 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
1852 gpr += 2;
1853
1854 /* Line LiveDrive Capture Volume + Switch */
1855 for (z = 0; z < 2; z++) {
1856 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
1857 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1858 }
1859 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
1860 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
1861 gpr += 4;
1862 }
1863
1864 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
1865 /* IEC958 Coax Playback Volume */
1866 for (z = 0; z < 2; z++)
1867 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001868 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 gpr += 2;
1870
1871 /* IEC958 Coax Capture Volume + Switch */
1872 for (z = 0; z < 2; z++) {
1873 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
1874 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1875 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001876 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
1877 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 -07001878 gpr += 4;
1879 }
1880
1881 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
1882 /* Line LiveDrive Playback Volume */
1883 for (z = 0; z < 2; z++)
1884 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
1885 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
1886 controls[i-1].id.index = 1;
1887 gpr += 2;
1888
1889 /* Line LiveDrive Capture Volume */
1890 for (z = 0; z < 2; z++) {
1891 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
1892 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1893 }
1894 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
1895 controls[i-1].id.index = 1;
1896 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
1897 controls[i-1].id.index = 1;
1898 gpr += 4;
1899 }
1900
1901 /*
1902 * Process tone control
1903 */
1904 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
1905 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
1906 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
1907 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
1908 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
1909 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
1910
1911 ctl = &controls[i + 0];
1912 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1913 strcpy(ctl->id.name, "Tone Control - Bass");
1914 ctl->vcount = 2;
1915 ctl->count = 10;
1916 ctl->min = 0;
1917 ctl->max = 40;
1918 ctl->value[0] = ctl->value[1] = 20;
1919 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1920 ctl = &controls[i + 1];
1921 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1922 strcpy(ctl->id.name, "Tone Control - Treble");
1923 ctl->vcount = 2;
1924 ctl->count = 10;
1925 ctl->min = 0;
1926 ctl->max = 40;
1927 ctl->value[0] = ctl->value[1] = 20;
1928 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1929
1930#define BASS_GPR 0x8c
1931#define TREBLE_GPR 0x96
1932
1933 for (z = 0; z < 5; z++) {
1934 int j;
1935 for (j = 0; j < 2; j++) {
1936 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1937 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1938 }
1939 }
1940 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
1941 int j, k, l, d;
1942 for (j = 0; j < 2; j++) { /* left/right */
1943 k = 0xa0 + (z * 8) + (j * 4);
1944 l = 0xd0 + (z * 8) + (j * 4);
1945 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1946
1947 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
1948 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
1949 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
1950 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
1951 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
1952 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
1953
1954 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
1955 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
1956 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
1957 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
1958 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
1959 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
1960
1961 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
1962
1963 if (z == 2) /* center */
1964 break;
1965 }
1966 }
1967 i += 2;
1968
1969#undef BASS_GPR
1970#undef TREBLE_GPR
1971
1972 for (z = 0; z < 6; z++) {
1973 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1974 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1975 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1976 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1977 }
1978 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
1979 gpr += 2;
1980
1981 /*
1982 * Process outputs
1983 */
1984 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
1985 /* AC'97 Playback Volume */
1986
1987 for (z = 0; z < 2; z++)
1988 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
1989 }
1990
1991 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
1992 /* IEC958 Optical Raw Playback Switch */
1993
1994 for (z = 0; z < 2; z++) {
1995 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
1996 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1997 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1998 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1999#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2000 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2001#endif
2002 }
2003
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002004 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 -07002005 gpr += 2;
2006 }
2007
2008 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2009 /* Headphone Playback Volume */
2010
2011 for (z = 0; z < 2; z++) {
2012 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2013 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2014 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2015 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2016 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2017 }
2018
2019 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2020 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2021 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2022 controls[i-1].id.index = 1;
2023 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2024 controls[i-1].id.index = 1;
2025
2026 gpr += 4;
2027 }
2028
2029 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2030 for (z = 0; z < 2; z++)
2031 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2032
2033 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2034 for (z = 0; z < 2; z++)
2035 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2036
2037 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2038#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2039 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2040 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2041#else
2042 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2043 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2044#endif
2045 }
2046
2047 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2048#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2049 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2050 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2051#else
2052 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2053 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2054#endif
2055 }
2056
2057#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2058 for (z = 0; z < 2; z++)
2059 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2060#endif
2061
2062 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2063 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2064
2065 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002066 if (emu->card_capabilities->sblive51) {
2067 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2068 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2069 *
2070 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2071 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2072 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2073 * channel. Multitrack recorders will still see the center/lfe output signal
2074 * on the second and third channels.
2075 */
2076 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2077 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2078 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2079 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2080 for (z = 4; z < 14; z++)
2081 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2082 } else {
2083 for (z = 0; z < 16; z++)
2084 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
Lee Revell2b637da2005-03-30 13:51:18 +02002086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
2088 if (gpr > tmp) {
2089 snd_BUG();
2090 err = -EIO;
2091 goto __err;
2092 }
2093 if (i > SND_EMU10K1_GPR_CONTROLS) {
2094 snd_BUG();
2095 err = -EIO;
2096 goto __err;
2097 }
2098
2099 /* clear remaining instruction memory */
2100 while (ptr < 0x200)
2101 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2102
2103 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2104 goto __err;
2105 seg = snd_enter_user();
2106 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002107 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 err = snd_emu10k1_icode_poke(emu, icode);
2109 snd_leave_user(seg);
2110 if (err >= 0)
2111 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2112 __err:
2113 kfree(ipcm);
2114 kfree(controls);
2115 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002116 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 kfree(icode);
2118 }
2119 return err;
2120}
2121
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002122int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123{
Takashi Iwai09668b42005-11-17 16:14:10 +01002124 spin_lock_init(&emu->fx8010.irq_lock);
2125 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if (emu->audigy)
2127 return _snd_emu10k1_audigy_init_efx(emu);
2128 else
2129 return _snd_emu10k1_init_efx(emu);
2130}
2131
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002132void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133{
2134 /* stop processor */
2135 if (emu->audigy)
2136 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2137 else
2138 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2139}
2140
2141#if 0 // FIXME: who use them?
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002142int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002144 if (output < 0 || output >= 6)
2145 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2147 return 0;
2148}
2149
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002150int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002152 if (output < 0 || output >= 6)
2153 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2155 return 0;
2156}
2157#endif
2158
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002159int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
2161 u8 size_reg = 0;
2162
2163 /* size is in samples */
2164 if (size != 0) {
2165 size = (size - 1) >> 13;
2166
2167 while (size) {
2168 size >>= 1;
2169 size_reg++;
2170 }
2171 size = 0x2000 << size_reg;
2172 }
2173 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2174 return 0;
2175 spin_lock_irq(&emu->emu_lock);
2176 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2177 spin_unlock_irq(&emu->emu_lock);
2178 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2179 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2180 if (emu->fx8010.etram_pages.area != NULL) {
2181 snd_dma_free_pages(&emu->fx8010.etram_pages);
2182 emu->fx8010.etram_pages.area = NULL;
2183 emu->fx8010.etram_pages.bytes = 0;
2184 }
2185
2186 if (size > 0) {
2187 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2188 size * 2, &emu->fx8010.etram_pages) < 0)
2189 return -ENOMEM;
2190 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2191 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2192 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2193 spin_lock_irq(&emu->emu_lock);
2194 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002195 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197
2198 return 0;
2199}
2200
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002201static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202{
2203 return 0;
2204}
2205
2206static void copy_string(char *dst, char *src, char *null, int idx)
2207{
2208 if (src == NULL)
2209 sprintf(dst, "%s %02X", null, idx);
2210 else
2211 strcpy(dst, src);
2212}
2213
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002214static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2215 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
2217 char **fxbus, **extin, **extout;
2218 unsigned short fxbus_mask, extin_mask, extout_mask;
2219 int res;
2220
2221 memset(info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 info->internal_tram_size = emu->fx8010.itram_size;
2223 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2224 fxbus = fxbuses;
2225 extin = emu->audigy ? audigy_ins : creative_ins;
2226 extout = emu->audigy ? audigy_outs : creative_outs;
2227 fxbus_mask = emu->fx8010.fxbus_mask;
2228 extin_mask = emu->fx8010.extin_mask;
2229 extout_mask = emu->fx8010.extout_mask;
2230 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2231 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2232 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2233 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2234 }
2235 for (res = 16; res < 32; res++, extout++)
2236 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2237 info->gpr_controls = emu->fx8010.gpr_count;
2238 return 0;
2239}
2240
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002241static 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 -07002242{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002243 struct snd_emu10k1 *emu = hw->private_data;
2244 struct snd_emu10k1_fx8010_info *info;
2245 struct snd_emu10k1_fx8010_code *icode;
2246 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 unsigned int addr;
2248 void __user *argp = (void __user *)arg;
2249 int res;
2250
2251 switch (cmd) {
2252 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002253 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 if (!info)
2255 return -ENOMEM;
2256 if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
2257 kfree(info);
2258 return res;
2259 }
2260 if (copy_to_user(argp, info, sizeof(*info))) {
2261 kfree(info);
2262 return -EFAULT;
2263 }
2264 kfree(info);
2265 return 0;
2266 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2267 if (!capable(CAP_SYS_ADMIN))
2268 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002269 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (icode == NULL)
2271 return -ENOMEM;
2272 if (copy_from_user(icode, argp, sizeof(*icode))) {
2273 kfree(icode);
2274 return -EFAULT;
2275 }
2276 res = snd_emu10k1_icode_poke(emu, icode);
2277 kfree(icode);
2278 return res;
2279 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002280 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (icode == NULL)
2282 return -ENOMEM;
2283 if (copy_from_user(icode, argp, sizeof(*icode))) {
2284 kfree(icode);
2285 return -EFAULT;
2286 }
2287 res = snd_emu10k1_icode_peek(emu, icode);
2288 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2289 kfree(icode);
2290 return -EFAULT;
2291 }
2292 kfree(icode);
2293 return res;
2294 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002295 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (ipcm == NULL)
2297 return -ENOMEM;
2298 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2299 kfree(ipcm);
2300 return -EFAULT;
2301 }
2302 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2303 kfree(ipcm);
2304 return res;
2305 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002306 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 if (ipcm == NULL)
2308 return -ENOMEM;
2309 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2310 kfree(ipcm);
2311 return -EFAULT;
2312 }
2313 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2314 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2315 kfree(ipcm);
2316 return -EFAULT;
2317 }
2318 kfree(ipcm);
2319 return res;
2320 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2321 if (!capable(CAP_SYS_ADMIN))
2322 return -EPERM;
2323 if (get_user(addr, (unsigned int __user *)argp))
2324 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002325 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002327 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 return res;
2329 case SNDRV_EMU10K1_IOCTL_STOP:
2330 if (!capable(CAP_SYS_ADMIN))
2331 return -EPERM;
2332 if (emu->audigy)
2333 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2334 else
2335 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2336 return 0;
2337 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2338 if (!capable(CAP_SYS_ADMIN))
2339 return -EPERM;
2340 if (emu->audigy)
2341 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2342 else
2343 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2344 return 0;
2345 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2346 if (!capable(CAP_SYS_ADMIN))
2347 return -EPERM;
2348 if (emu->audigy)
2349 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2350 else
2351 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2352 udelay(10);
2353 if (emu->audigy)
2354 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2355 else
2356 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2357 return 0;
2358 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2359 if (!capable(CAP_SYS_ADMIN))
2360 return -EPERM;
2361 if (get_user(addr, (unsigned int __user *)argp))
2362 return -EFAULT;
2363 if (addr > 0x1ff)
2364 return -EINVAL;
2365 if (emu->audigy)
2366 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2367 else
2368 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2369 udelay(10);
2370 if (emu->audigy)
2371 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2372 else
2373 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2374 return 0;
2375 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2376 if (emu->audigy)
2377 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2378 else
2379 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2380 if (put_user(addr, (unsigned int __user *)argp))
2381 return -EFAULT;
2382 return 0;
2383 }
2384 return -ENOTTY;
2385}
2386
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002387static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388{
2389 return 0;
2390}
2391
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002392int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002394 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 int err;
2396
2397 if (rhwdep)
2398 *rhwdep = NULL;
2399 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2400 return err;
2401 strcpy(hw->name, "EMU10K1 (FX8010)");
2402 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2403 hw->ops.open = snd_emu10k1_fx8010_open;
2404 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2405 hw->ops.release = snd_emu10k1_fx8010_release;
2406 hw->private_data = emu;
2407 if (rhwdep)
2408 *rhwdep = hw;
2409 return 0;
2410}
Takashi Iwai09668b42005-11-17 16:14:10 +01002411
2412#ifdef CONFIG_PM
2413int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2414{
2415 int len;
2416
2417 len = emu->audigy ? 0x200 : 0x100;
2418 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2419 if (! emu->saved_gpr)
2420 return -ENOMEM;
2421 len = emu->audigy ? 0x100 : 0xa0;
2422 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2423 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2424 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2425 return -ENOMEM;
2426 len = emu->audigy ? 2 * 1024 : 2 * 512;
2427 emu->saved_icode = vmalloc(len * 4);
2428 if (! emu->saved_icode)
2429 return -ENOMEM;
2430 return 0;
2431}
2432
2433void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2434{
2435 kfree(emu->saved_gpr);
2436 kfree(emu->tram_val_saved);
2437 kfree(emu->tram_addr_saved);
2438 vfree(emu->saved_icode);
2439}
2440
2441/*
2442 * save/restore GPR, TRAM and codes
2443 */
2444void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2445{
2446 int i, len;
2447
2448 len = emu->audigy ? 0x200 : 0x100;
2449 for (i = 0; i < len; i++)
2450 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2451
2452 len = emu->audigy ? 0x100 : 0xa0;
2453 for (i = 0; i < len; i++) {
2454 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2455 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2456 if (emu->audigy) {
2457 emu->tram_addr_saved[i] >>= 12;
2458 emu->tram_addr_saved[i] |=
2459 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2460 }
2461 }
2462
2463 len = emu->audigy ? 2 * 1024 : 2 * 512;
2464 for (i = 0; i < len; i++)
2465 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2466}
2467
2468void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2469{
2470 int i, len;
2471
2472 /* set up TRAM */
2473 if (emu->fx8010.etram_pages.bytes > 0) {
2474 unsigned size, size_reg = 0;
2475 size = emu->fx8010.etram_pages.bytes / 2;
2476 size = (size - 1) >> 13;
2477 while (size) {
2478 size >>= 1;
2479 size_reg++;
2480 }
2481 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2482 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2483 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2484 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2485 }
2486
2487 if (emu->audigy)
2488 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2489 else
2490 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2491
2492 len = emu->audigy ? 0x200 : 0x100;
2493 for (i = 0; i < len; i++)
2494 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2495
2496 len = emu->audigy ? 0x100 : 0xa0;
2497 for (i = 0; i < len; i++) {
2498 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2499 emu->tram_val_saved[i]);
2500 if (! emu->audigy)
2501 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2502 emu->tram_addr_saved[i]);
2503 else {
2504 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2505 emu->tram_addr_saved[i] << 12);
2506 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2507 emu->tram_addr_saved[i] >> 20);
2508 }
2509 }
2510
2511 len = emu->audigy ? 2 * 1024 : 2 * 512;
2512 for (i = 0; i < len; i++)
2513 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2514
2515 /* start FX processor when the DSP code is updated */
2516 if (emu->audigy)
2517 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2518 else
2519 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2520}
2521#endif