blob: 00fc904c251dc335fc77c87b845eb0efde703cd6 [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
270static const u32 db_table[101] = {
271 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
272 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
273 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
274 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
275 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
276 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
277 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
278 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
279 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
280 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
281 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
282 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
283 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
284 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
285 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
286 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
287 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
288 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
289 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
290 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
291 0x7fffffff,
292};
293
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100294/* EMU10k1/EMU10k2 DSP control db gain */
295static DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297static const u32 onoff_table[2] = {
298 0x00000000, 0x00000001
299};
300
301/*
302 */
303
304static inline mm_segment_t snd_enter_user(void)
305{
306 mm_segment_t fs = get_fs();
307 set_fs(get_ds());
308 return fs;
309}
310
311static inline void snd_leave_user(mm_segment_t fs)
312{
313 set_fs(fs);
314}
315
316/*
317 * controls
318 */
319
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100320static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100322 struct snd_emu10k1_fx8010_ctl *ctl =
323 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 if (ctl->min == 0 && ctl->max == 1)
326 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
327 else
328 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
329 uinfo->count = ctl->vcount;
330 uinfo->value.integer.min = ctl->min;
331 uinfo->value.integer.max = ctl->max;
332 return 0;
333}
334
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100335static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100337 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
338 struct snd_emu10k1_fx8010_ctl *ctl =
339 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 unsigned long flags;
341 unsigned int i;
342
343 spin_lock_irqsave(&emu->reg_lock, flags);
344 for (i = 0; i < ctl->vcount; i++)
345 ucontrol->value.integer.value[i] = ctl->value[i];
346 spin_unlock_irqrestore(&emu->reg_lock, flags);
347 return 0;
348}
349
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100350static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100352 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
353 struct snd_emu10k1_fx8010_ctl *ctl =
354 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 unsigned long flags;
356 unsigned int nval, val;
357 unsigned int i, j;
358 int change = 0;
359
360 spin_lock_irqsave(&emu->reg_lock, flags);
361 for (i = 0; i < ctl->vcount; i++) {
362 nval = ucontrol->value.integer.value[i];
363 if (nval < ctl->min)
364 nval = ctl->min;
365 if (nval > ctl->max)
366 nval = ctl->max;
367 if (nval != ctl->value[i])
368 change = 1;
369 val = ctl->value[i] = nval;
370 switch (ctl->translation) {
371 case EMU10K1_GPR_TRANSLATION_NONE:
372 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
373 break;
374 case EMU10K1_GPR_TRANSLATION_TABLE100:
375 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
376 break;
377 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200378 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
379 change = -EIO;
380 goto __error;
381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 for (j = 0; j < 5; j++)
383 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
384 break;
385 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200386 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
387 change = -EIO;
388 goto __error;
389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 for (j = 0; j < 5; j++)
391 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
392 break;
393 case EMU10K1_GPR_TRANSLATION_ONOFF:
394 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
395 break;
396 }
397 }
398 __error:
399 spin_unlock_irqrestore(&emu->reg_lock, flags);
400 return change;
401}
402
403/*
404 * Interrupt handler
405 */
406
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100407static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100409 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
411 irq = emu->fx8010.irq_handlers;
412 while (irq) {
413 nirq = irq->next; /* irq ptr can be removed from list */
414 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
415 if (irq->handler)
416 irq->handler(emu, irq->private_data);
417 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
418 }
419 irq = nirq;
420 }
421}
422
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100423int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
424 snd_fx8010_irq_handler_t *handler,
425 unsigned char gpr_running,
426 void *private_data,
427 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100429 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 unsigned long flags;
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
433 if (irq == NULL)
434 return -ENOMEM;
435 irq->handler = handler;
436 irq->gpr_running = gpr_running;
437 irq->private_data = private_data;
438 irq->next = NULL;
439 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
440 if (emu->fx8010.irq_handlers == NULL) {
441 emu->fx8010.irq_handlers = irq;
442 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
443 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
444 } else {
445 irq->next = emu->fx8010.irq_handlers;
446 emu->fx8010.irq_handlers = irq;
447 }
448 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
449 if (r_irq)
450 *r_irq = irq;
451 return 0;
452}
453
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100454int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
455 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100457 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 unsigned long flags;
459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
461 if ((tmp = emu->fx8010.irq_handlers) == irq) {
462 emu->fx8010.irq_handlers = tmp->next;
463 if (emu->fx8010.irq_handlers == NULL) {
464 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
465 emu->dsp_interrupt = NULL;
466 }
467 } else {
468 while (tmp && tmp->next != irq)
469 tmp = tmp->next;
470 if (tmp)
471 tmp->next = tmp->next->next;
472 }
473 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
474 kfree(irq);
475 return 0;
476}
477
478/*************************************************************************
479 * EMU10K1 effect manager
480 *************************************************************************/
481
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100482static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
483 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 u32 op, u32 r, u32 a, u32 x, u32 y)
485{
486 u_int32_t *code;
487 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200488 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 set_bit(*ptr, icode->code_valid);
490 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
491 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
492 (*ptr)++;
493}
494
495#define OP(icode, ptr, op, r, a, x, y) \
496 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
497
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100498static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
499 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 u32 op, u32 r, u32 a, u32 x, u32 y)
501{
502 u_int32_t *code;
503 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200504 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 set_bit(*ptr, icode->code_valid);
506 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
507 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
508 (*ptr)++;
509}
510
511#define A_OP(icode, ptr, op, r, a, x, y) \
512 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
513
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100514static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
517 snd_emu10k1_ptr_write(emu, pc, 0, data);
518}
519
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100520unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521{
522 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
523 return snd_emu10k1_ptr_read(emu, pc, 0);
524}
525
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100526static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
527 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 int gpr;
530 u32 val;
531
532 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
533 if (!test_bit(gpr, icode->gpr_valid))
534 continue;
535 if (get_user(val, &icode->gpr_map[gpr]))
536 return -EFAULT;
537 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
538 }
539 return 0;
540}
541
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100542static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
543 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 int gpr;
546 u32 val;
547
548 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
549 set_bit(gpr, icode->gpr_valid);
550 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
551 if (put_user(val, &icode->gpr_map[gpr]))
552 return -EFAULT;
553 }
554 return 0;
555}
556
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100557static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
558 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
560 int tram;
561 u32 addr, val;
562
563 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
564 if (!test_bit(tram, icode->tram_valid))
565 continue;
566 if (get_user(val, &icode->tram_data_map[tram]) ||
567 get_user(addr, &icode->tram_addr_map[tram]))
568 return -EFAULT;
569 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
570 if (!emu->audigy) {
571 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
572 } else {
573 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
574 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
575 }
576 }
577 return 0;
578}
579
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100580static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
581 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
583 int tram;
584 u32 val, addr;
585
586 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
587 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
588 set_bit(tram, icode->tram_valid);
589 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
590 if (!emu->audigy) {
591 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
592 } else {
593 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
594 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
595 }
596 if (put_user(val, &icode->tram_data_map[tram]) ||
597 put_user(addr, &icode->tram_addr_map[tram]))
598 return -EFAULT;
599 }
600 return 0;
601}
602
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100603static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
604 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 u32 pc, lo, hi;
607
608 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
609 if (!test_bit(pc / 2, icode->code_valid))
610 continue;
611 if (get_user(lo, &icode->code[pc + 0]) ||
612 get_user(hi, &icode->code[pc + 1]))
613 return -EFAULT;
614 snd_emu10k1_efx_write(emu, pc + 0, lo);
615 snd_emu10k1_efx_write(emu, pc + 1, hi);
616 }
617 return 0;
618}
619
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100620static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
621 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 u32 pc;
624
625 memset(icode->code_valid, 0, sizeof(icode->code_valid));
626 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
627 set_bit(pc / 2, icode->code_valid);
628 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
629 return -EFAULT;
630 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
631 return -EFAULT;
632 }
633 return 0;
634}
635
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100636static struct snd_emu10k1_fx8010_ctl *
637snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100639 struct snd_emu10k1_fx8010_ctl *ctl;
640 struct snd_kcontrol *kcontrol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 struct list_head *list;
642
643 list_for_each(list, &emu->fx8010.gpr_ctl) {
644 ctl = emu10k1_gpr_ctl(list);
645 kcontrol = ctl->kcontrol;
646 if (kcontrol->id.iface == id->iface &&
647 !strcmp(kcontrol->id.name, id->name) &&
648 kcontrol->id.index == id->index)
649 return ctl;
650 }
651 return NULL;
652}
653
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100654static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
655 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100658 struct snd_ctl_elem_id __user *_id;
659 struct snd_ctl_elem_id id;
660 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
661 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 int err;
663
664 for (i = 0, _id = icode->gpr_del_controls;
665 i < icode->gpr_del_control_count; i++, _id++) {
666 if (copy_from_user(&id, _id, sizeof(id)))
667 return -EFAULT;
668 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
669 return -ENOENT;
670 }
671 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
672 if (! gctl)
673 return -ENOMEM;
674 err = 0;
675 for (i = 0, _gctl = icode->gpr_add_controls;
676 i < icode->gpr_add_control_count; i++, _gctl++) {
677 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
678 err = -EFAULT;
679 goto __error;
680 }
681 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
682 continue;
683 down_read(&emu->card->controls_rwsem);
684 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
685 up_read(&emu->card->controls_rwsem);
686 err = -EEXIST;
687 goto __error;
688 }
689 up_read(&emu->card->controls_rwsem);
690 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
691 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
692 err = -EINVAL;
693 goto __error;
694 }
695 }
696 for (i = 0, _gctl = icode->gpr_list_controls;
697 i < icode->gpr_list_control_count; i++, _gctl++) {
698 /* FIXME: we need to check the WRITE access */
699 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
700 err = -EFAULT;
701 goto __error;
702 }
703 }
704 __error:
705 kfree(gctl);
706 return err;
707}
708
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100709static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100711 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100713 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 kctl->private_value = 0;
715 list_del(&ctl->list);
716 kfree(ctl);
717}
718
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100719static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
720 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
722 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100723 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
724 struct snd_emu10k1_fx8010_control_gpr *gctl;
725 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
726 struct snd_kcontrol_new knew;
727 struct snd_kcontrol *kctl;
728 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 int err = 0;
730
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100731 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
733 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
734 if (!val || !gctl || !nctl) {
735 err = -ENOMEM;
736 goto __error;
737 }
738
739 for (i = 0, _gctl = icode->gpr_add_controls;
740 i < icode->gpr_add_control_count; i++, _gctl++) {
741 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
742 err = -EFAULT;
743 goto __error;
744 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200745 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
746 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
747 err = -EINVAL;
748 goto __error;
749 }
750 if (! gctl->id.name[0]) {
751 err = -EINVAL;
752 goto __error;
753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
755 memset(&knew, 0, sizeof(knew));
756 knew.iface = gctl->id.iface;
757 knew.name = gctl->id.name;
758 knew.index = gctl->id.index;
759 knew.device = gctl->id.device;
760 knew.subdevice = gctl->id.subdevice;
761 knew.info = snd_emu10k1_gpr_ctl_info;
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100762 if (gctl->tlv.p) {
763 knew.tlv.p = gctl->tlv.p;
764 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
765 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 knew.get = snd_emu10k1_gpr_ctl_get;
768 knew.put = snd_emu10k1_gpr_ctl_put;
769 memset(nctl, 0, sizeof(*nctl));
770 nctl->vcount = gctl->vcount;
771 nctl->count = gctl->count;
772 for (j = 0; j < 32; j++) {
773 nctl->gpr[j] = gctl->gpr[j];
774 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
775 val->value.integer.value[j] = gctl->value[j];
776 }
777 nctl->min = gctl->min;
778 nctl->max = gctl->max;
779 nctl->translation = gctl->translation;
780 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100781 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (ctl == NULL) {
783 err = -ENOMEM;
784 goto __error;
785 }
786 knew.private_value = (unsigned long)ctl;
787 *ctl = *nctl;
788 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
789 kfree(ctl);
790 goto __error;
791 }
792 kctl->private_free = snd_emu10k1_ctl_private_free;
793 ctl->kcontrol = kctl;
794 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
795 } else {
796 /* overwrite */
797 nctl->list = ctl->list;
798 nctl->kcontrol = ctl->kcontrol;
799 *ctl = *nctl;
800 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
801 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
802 }
803 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
804 }
805 __error:
806 kfree(nctl);
807 kfree(gctl);
808 kfree(val);
809 return err;
810}
811
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100812static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
813 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100816 struct snd_ctl_elem_id id;
817 struct snd_ctl_elem_id __user *_id;
818 struct snd_emu10k1_fx8010_ctl *ctl;
819 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
821 for (i = 0, _id = icode->gpr_del_controls;
822 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200823 if (copy_from_user(&id, _id, sizeof(id)))
824 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 down_write(&card->controls_rwsem);
826 ctl = snd_emu10k1_look_for_ctl(emu, &id);
827 if (ctl)
828 snd_ctl_remove(card, ctl->kcontrol);
829 up_write(&card->controls_rwsem);
830 }
831 return 0;
832}
833
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100834static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
835 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
837 unsigned int i = 0, j;
838 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100839 struct snd_emu10k1_fx8010_control_gpr *gctl;
840 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
841 struct snd_emu10k1_fx8010_ctl *ctl;
842 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 struct list_head *list;
844
845 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
846 if (! gctl)
847 return -ENOMEM;
848
849 _gctl = icode->gpr_list_controls;
850 list_for_each(list, &emu->fx8010.gpr_ctl) {
851 ctl = emu10k1_gpr_ctl(list);
852 total++;
853 if (_gctl && i < icode->gpr_list_control_count) {
854 memset(gctl, 0, sizeof(*gctl));
855 id = &ctl->kcontrol->id;
856 gctl->id.iface = id->iface;
857 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
858 gctl->id.index = id->index;
859 gctl->id.device = id->device;
860 gctl->id.subdevice = id->subdevice;
861 gctl->vcount = ctl->vcount;
862 gctl->count = ctl->count;
863 for (j = 0; j < 32; j++) {
864 gctl->gpr[j] = ctl->gpr[j];
865 gctl->value[j] = ctl->value[j];
866 }
867 gctl->min = ctl->min;
868 gctl->max = ctl->max;
869 gctl->translation = ctl->translation;
870 if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
871 kfree(gctl);
872 return -EFAULT;
873 }
874 _gctl++;
875 i++;
876 }
877 }
878 icode->gpr_list_control_total = total;
879 kfree(gctl);
880 return 0;
881}
882
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100883static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
884 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
886 int err = 0;
887
Ingo Molnar62932df2006-01-16 16:34:20 +0100888 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
890 goto __error;
891 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
892 /* stop FX processor - this may be dangerous, but it's better to miss
893 some samples than generate wrong ones - [jk] */
894 if (emu->audigy)
895 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
896 else
897 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
898 /* ok, do the main job */
899 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
900 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
901 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
902 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
903 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
904 goto __error;
905 /* start FX processor when the DSP code is updated */
906 if (emu->audigy)
907 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
908 else
909 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
910 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100911 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 return err;
913}
914
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100915static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
916 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917{
918 int err;
919
Ingo Molnar62932df2006-01-16 16:34:20 +0100920 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
922 /* ok, do the main job */
923 err = snd_emu10k1_gpr_peek(emu, icode);
924 if (err >= 0)
925 err = snd_emu10k1_tram_peek(emu, icode);
926 if (err >= 0)
927 err = snd_emu10k1_code_peek(emu, icode);
928 if (err >= 0)
929 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100930 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 return err;
932}
933
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100934static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
935 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
937 unsigned int i;
938 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100939 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
942 return -EINVAL;
943 if (ipcm->channels > 32)
944 return -EINVAL;
945 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100946 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 spin_lock_irq(&emu->reg_lock);
948 if (pcm->opened) {
949 err = -EBUSY;
950 goto __error;
951 }
952 if (ipcm->channels == 0) { /* remove */
953 pcm->valid = 0;
954 } else {
955 /* FIXME: we need to add universal code to the PCM transfer routine */
956 if (ipcm->channels != 2) {
957 err = -EINVAL;
958 goto __error;
959 }
960 pcm->valid = 1;
961 pcm->opened = 0;
962 pcm->channels = ipcm->channels;
963 pcm->tram_start = ipcm->tram_start;
964 pcm->buffer_size = ipcm->buffer_size;
965 pcm->gpr_size = ipcm->gpr_size;
966 pcm->gpr_count = ipcm->gpr_count;
967 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
968 pcm->gpr_ptr = ipcm->gpr_ptr;
969 pcm->gpr_trigger = ipcm->gpr_trigger;
970 pcm->gpr_running = ipcm->gpr_running;
971 for (i = 0; i < pcm->channels; i++)
972 pcm->etram[i] = ipcm->etram[i];
973 }
974 __error:
975 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +0100976 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 return err;
978}
979
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100980static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
981 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
983 unsigned int i;
984 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100985 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
988 return -EINVAL;
989 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100990 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 spin_lock_irq(&emu->reg_lock);
992 ipcm->channels = pcm->channels;
993 ipcm->tram_start = pcm->tram_start;
994 ipcm->buffer_size = pcm->buffer_size;
995 ipcm->gpr_size = pcm->gpr_size;
996 ipcm->gpr_ptr = pcm->gpr_ptr;
997 ipcm->gpr_count = pcm->gpr_count;
998 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
999 ipcm->gpr_trigger = pcm->gpr_trigger;
1000 ipcm->gpr_running = pcm->gpr_running;
1001 for (i = 0; i < pcm->channels; i++)
1002 ipcm->etram[i] = pcm->etram[i];
1003 ipcm->res1 = ipcm->res2 = 0;
1004 ipcm->pad = 0;
1005 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001006 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return err;
1008}
1009
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001010#define SND_EMU10K1_GPR_CONTROLS 44
1011#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1013#define SND_EMU10K1_CAPTURE_CHANNELS 4
1014
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001015static void __devinit
1016snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1017 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018{
1019 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1020 strcpy(ctl->id.name, name);
1021 ctl->vcount = ctl->count = 1;
1022 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1023 ctl->min = 0;
1024 ctl->max = 100;
James Courtier-Dutton31508f82006-07-22 17:02:10 +01001025 ctl->tlv.p = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1027}
1028
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001029static void __devinit
1030snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1031 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
1033 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1034 strcpy(ctl->id.name, name);
1035 ctl->vcount = ctl->count = 2;
1036 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1037 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1038 ctl->min = 0;
1039 ctl->max = 100;
James Courtier-Dutton31508f82006-07-22 17:02:10 +01001040 ctl->tlv.p = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1042}
1043
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001044static void __devinit
1045snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1046 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047{
1048 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1049 strcpy(ctl->id.name, name);
1050 ctl->vcount = ctl->count = 1;
1051 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1052 ctl->min = 0;
1053 ctl->max = 1;
1054 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1055}
1056
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001057static void __devinit
1058snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1059 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060{
1061 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1062 strcpy(ctl->id.name, name);
1063 ctl->vcount = ctl->count = 2;
1064 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1065 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1066 ctl->min = 0;
1067 ctl->max = 1;
1068 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1069}
1070
1071
1072/*
1073 * initial DSP configuration for Audigy
1074 */
1075
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001076static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077{
1078 int err, i, z, gpr, nctl;
1079 const int playback = 10;
1080 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1081 const int stereo_mix = capture + 2;
1082 const int tmp = 0x88;
1083 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001084 struct snd_emu10k1_fx8010_code *icode = NULL;
1085 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 u32 *gpr_map;
1087 mm_segment_t seg;
1088
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001089 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001090 (icode->gpr_map = (u_int32_t __user *)
1091 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1092 GFP_KERNEL)) == NULL ||
1093 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1094 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 err = -ENOMEM;
1096 goto __err;
1097 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001098 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 icode->tram_data_map = icode->gpr_map + 512;
1101 icode->tram_addr_map = icode->tram_data_map + 256;
1102 icode->code = icode->tram_addr_map + 256;
1103
1104 /* clear free GPRs */
1105 for (i = 0; i < 512; i++)
1106 set_bit(i, icode->gpr_valid);
1107
1108 /* clear TRAM data & address lines */
1109 for (i = 0; i < 256; i++)
1110 set_bit(i, icode->tram_valid);
1111
1112 strcpy(icode->name, "Audigy DSP code for ALSA");
1113 ptr = 0;
1114 nctl = 0;
1115 gpr = stereo_mix + 10;
1116
1117 /* stop FX processor */
1118 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1119
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001120#if 0
1121 /* FIX: jcd test */
1122 for (z = 0; z < 80; z=z+2) {
1123 A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
1124 A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
1125 }
1126#endif /* jcd test */
1127#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 /* PCM front Playback Volume (independent from stereo mix) */
1129 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1130 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1131 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1132 gpr += 2;
1133
1134 /* PCM Surround Playback (independent from stereo mix) */
1135 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1136 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1137 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1138 gpr += 2;
1139
1140 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001141 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1143 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1144 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1145 gpr += 2;
1146 }
1147
1148 /* PCM Center Playback (independent from stereo mix) */
1149 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1150 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1151 gpr++;
1152
1153 /* PCM LFE Playback (independent from stereo mix) */
1154 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1155 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1156 gpr++;
1157
1158 /*
1159 * Stereo Mix
1160 */
1161 /* Wave (PCM) Playback Volume (will be renamed later) */
1162 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1163 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1164 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1165 gpr += 2;
1166
1167 /* Synth Playback */
1168 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1169 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1170 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1171 gpr += 2;
1172
1173 /* Wave (PCM) Capture */
1174 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1175 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1176 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1177 gpr += 2;
1178
1179 /* Synth Capture */
1180 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1181 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1182 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1183 gpr += 2;
1184
1185 /*
1186 * inputs
1187 */
1188#define A_ADD_VOLUME_IN(var,vol,input) \
1189A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1190
1191 /* AC'97 Playback Volume - used only for mic (renamed later) */
1192 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1193 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1194 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1195 gpr += 2;
1196 /* AC'97 Capture Volume - used only for mic */
1197 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1198 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1199 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1200 gpr += 2;
1201
1202 /* mic capture buffer */
1203 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1204
1205 /* Audigy CD Playback Volume */
1206 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1207 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1208 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001209 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 gpr, 0);
1211 gpr += 2;
1212 /* Audigy CD Capture Volume */
1213 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1214 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1215 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001216 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 gpr, 0);
1218 gpr += 2;
1219
1220 /* Optical SPDIF Playback Volume */
1221 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1222 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001223 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 gpr += 2;
1225 /* Optical SPDIF Capture Volume */
1226 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1227 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001228 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 gpr += 2;
1230
1231 /* Line2 Playback Volume */
1232 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1233 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1234 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001235 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 gpr, 0);
1237 gpr += 2;
1238 /* Line2 Capture Volume */
1239 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1240 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1241 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001242 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 gpr, 0);
1244 gpr += 2;
1245
1246 /* Philips ADC Playback Volume */
1247 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1248 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1249 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1250 gpr += 2;
1251 /* Philips ADC Capture Volume */
1252 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1253 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1254 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1255 gpr += 2;
1256
1257 /* Aux2 Playback Volume */
1258 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1259 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1260 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001261 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 gpr, 0);
1263 gpr += 2;
1264 /* Aux2 Capture Volume */
1265 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1266 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1267 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001268 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 gpr, 0);
1270 gpr += 2;
1271
1272 /* Stereo Mix Front Playback Volume */
1273 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1274 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1275 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1276 gpr += 2;
1277
1278 /* Stereo Mix Surround Playback */
1279 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1280 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1281 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1282 gpr += 2;
1283
1284 /* Stereo Mix Center Playback */
1285 /* Center = sub = Left/2 + Right/2 */
1286 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1287 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1288 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1289 gpr++;
1290
1291 /* Stereo Mix LFE Playback */
1292 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1293 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1294 gpr++;
1295
Lee Revell2b637da2005-03-30 13:51:18 +02001296 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 /* Stereo Mix Side Playback */
1298 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1299 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1300 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1301 gpr += 2;
1302 }
1303
1304 /*
1305 * outputs
1306 */
1307#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1308#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1309 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1310
1311#define _A_SWITCH(icode, ptr, dst, src, sw) \
1312 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1313#define A_SWITCH(icode, ptr, dst, src, sw) \
1314 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1315#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1316 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1317#define A_SWITCH_NEG(icode, ptr, dst, src) \
1318 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1319
1320
1321 /*
1322 * Process tone control
1323 */
1324 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1325 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1326 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 */
1327 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 */
1328 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1329 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 +02001330 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 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 */
1332 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 */
1333 }
1334
1335
1336 ctl = &controls[nctl + 0];
1337 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1338 strcpy(ctl->id.name, "Tone Control - Bass");
1339 ctl->vcount = 2;
1340 ctl->count = 10;
1341 ctl->min = 0;
1342 ctl->max = 40;
1343 ctl->value[0] = ctl->value[1] = 20;
1344 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1345 ctl = &controls[nctl + 1];
1346 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1347 strcpy(ctl->id.name, "Tone Control - Treble");
1348 ctl->vcount = 2;
1349 ctl->count = 10;
1350 ctl->min = 0;
1351 ctl->max = 40;
1352 ctl->value[0] = ctl->value[1] = 20;
1353 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1354
1355#define BASS_GPR 0x8c
1356#define TREBLE_GPR 0x96
1357
1358 for (z = 0; z < 5; z++) {
1359 int j;
1360 for (j = 0; j < 2; j++) {
1361 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1362 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1363 }
1364 }
1365 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1366 int j, k, l, d;
1367 for (j = 0; j < 2; j++) { /* left/right */
1368 k = 0xb0 + (z * 8) + (j * 4);
1369 l = 0xe0 + (z * 8) + (j * 4);
1370 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1371
1372 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1373 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1374 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1375 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1376 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1377 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1378
1379 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1380 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1381 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1382 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1383 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1384 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1385
1386 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1387
1388 if (z == 2) /* center */
1389 break;
1390 }
1391 }
1392 nctl += 2;
1393
1394#undef BASS_GPR
1395#undef TREBLE_GPR
1396
1397 for (z = 0; z < 8; z++) {
1398 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1399 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1400 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1401 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1402 }
1403 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1404 gpr += 2;
1405
1406 /* Master volume (will be renamed later) */
1407 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));
1408 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));
1409 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));
1410 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));
1411 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));
1412 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));
1413 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));
1414 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));
1415 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1416 gpr += 2;
1417
1418 /* analog speakers */
1419 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1420 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1421 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1422 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001423 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1425
1426 /* headphone */
1427 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1428
1429 /* digital outputs */
1430 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
1431
1432 /* IEC958 Optical Raw Playback Switch */
1433 gpr_map[gpr++] = 0;
1434 gpr_map[gpr++] = 0x1008;
1435 gpr_map[gpr++] = 0xffff0000;
1436 for (z = 0; z < 2; z++) {
1437 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1438 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1439 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1440 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1441 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1442 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1443 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1444 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1445 /* 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 +02001446 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1448 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1449 } else {
1450 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1451 }
1452 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001453 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 -07001454 gpr += 2;
1455
1456 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1457 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1458 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1459
1460 /* ADC buffer */
1461#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1462 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1463#else
1464 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1465 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1466#endif
1467
1468 /* EFX capture - capture the 16 EXTINs */
1469 for (z = 0; z < 16; z++) {
1470 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1471 }
1472
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001473#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 /*
1475 * ok, set up done..
1476 */
1477
1478 if (gpr > tmp) {
1479 snd_BUG();
1480 err = -EIO;
1481 goto __err;
1482 }
1483 /* clear remaining instruction memory */
1484 while (ptr < 0x400)
1485 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1486
1487 seg = snd_enter_user();
1488 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001489 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 err = snd_emu10k1_icode_poke(emu, icode);
1491 snd_leave_user(seg);
1492
1493 __err:
1494 kfree(controls);
1495 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001496 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 kfree(icode);
1498 }
1499 return err;
1500}
1501
1502
1503/*
1504 * initial DSP configuration for Emu10k1
1505 */
1506
1507/* when volume = max, then copy only to avoid volume modification */
1508/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001509static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510{
1511 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1512 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1513 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1514 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1515}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001516static 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 -07001517{
1518 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1519 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1520 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1521 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1522 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1523}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001524static 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 -07001525{
1526 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1527 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1528 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1529 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1530 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1531}
1532
1533#define VOLUME(icode, ptr, dst, src, vol) \
1534 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1535#define VOLUME_IN(icode, ptr, dst, src, vol) \
1536 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1537#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1538 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1539#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1540 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1541#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1542 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1543#define _SWITCH(icode, ptr, dst, src, sw) \
1544 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1545#define SWITCH(icode, ptr, dst, src, sw) \
1546 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1547#define SWITCH_IN(icode, ptr, dst, src, sw) \
1548 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1549#define _SWITCH_NEG(icode, ptr, dst, src) \
1550 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1551#define SWITCH_NEG(icode, ptr, dst, src) \
1552 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1553
1554
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001555static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556{
1557 int err, i, z, gpr, tmp, playback, capture;
1558 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001559 struct snd_emu10k1_fx8010_code *icode;
1560 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1561 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 u32 *gpr_map;
1563 mm_segment_t seg;
1564
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001565 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001567 if ((icode->gpr_map = (u_int32_t __user *)
1568 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1569 GFP_KERNEL)) == NULL ||
1570 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1571 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1572 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001573 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 err = -ENOMEM;
1575 goto __err;
1576 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001577 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
1579 icode->tram_data_map = icode->gpr_map + 256;
1580 icode->tram_addr_map = icode->tram_data_map + 160;
1581 icode->code = icode->tram_addr_map + 160;
1582
1583 /* clear free GPRs */
1584 for (i = 0; i < 256; i++)
1585 set_bit(i, icode->gpr_valid);
1586
1587 /* clear TRAM data & address lines */
1588 for (i = 0; i < 160; i++)
1589 set_bit(i, icode->tram_valid);
1590
1591 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1592 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001593 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 playback = SND_EMU10K1_INPUTS;
1595 /* we have 6 playback channels and tone control doubles */
1596 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1597 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1598 tmp = 0x88; /* we need 4 temporary GPR */
1599 /* from 0x8c to 0xff is the area for tone control */
1600
1601 /* stop FX processor */
1602 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1603
1604 /*
1605 * Process FX Buses
1606 */
1607 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1608 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1609 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1610 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1611 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1612 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1613 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1614 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1615 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1616 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001617 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1618 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
1620 /* Raw S/PDIF PCM */
1621 ipcm->substream = 0;
1622 ipcm->channels = 2;
1623 ipcm->tram_start = 0;
1624 ipcm->buffer_size = (64 * 1024) / 2;
1625 ipcm->gpr_size = gpr++;
1626 ipcm->gpr_ptr = gpr++;
1627 ipcm->gpr_count = gpr++;
1628 ipcm->gpr_tmpcount = gpr++;
1629 ipcm->gpr_trigger = gpr++;
1630 ipcm->gpr_running = gpr++;
1631 ipcm->etram[0] = 0;
1632 ipcm->etram[1] = 1;
1633
1634 gpr_map[gpr + 0] = 0xfffff000;
1635 gpr_map[gpr + 1] = 0xffff0000;
1636 gpr_map[gpr + 2] = 0x70000000;
1637 gpr_map[gpr + 3] = 0x00000007;
1638 gpr_map[gpr + 4] = 0x001f << 11;
1639 gpr_map[gpr + 5] = 0x001c << 11;
1640 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1641 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1642 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1643 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1644 gpr_map[gpr + 10] = 1<<11;
1645 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1646 gpr_map[gpr + 12] = 0;
1647
1648 /* if the trigger flag is not set, skip */
1649 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1650 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1651 /* if the running flag is set, we're running */
1652 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1653 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1654 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1655 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1656 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1657 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1658 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1659
1660 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1661 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1662 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1663 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1664
1665 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1666 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1667 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1668 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1669 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1670
1671 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1672 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1673 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1674 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1675 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1676
1677 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1678 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1679 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1680 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1681 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1682
1683 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1684 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1685 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1686 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1687 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1688
1689 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1690 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1691
1692 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1693 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1694
1695 /* 24: */
1696 gpr += 13;
1697
1698 /* Wave Playback Volume */
1699 for (z = 0; z < 2; z++)
1700 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1701 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1702 gpr += 2;
1703
1704 /* Wave Surround Playback Volume */
1705 for (z = 0; z < 2; z++)
1706 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1707 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1708 gpr += 2;
1709
1710 /* Wave Center/LFE Playback Volume */
1711 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1712 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1713 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1714 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1715 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1716 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1717
1718 /* Wave Capture Volume + Switch */
1719 for (z = 0; z < 2; z++) {
1720 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1721 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1722 }
1723 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1724 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1725 gpr += 4;
1726
1727 /* Synth Playback Volume */
1728 for (z = 0; z < 2; z++)
1729 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1730 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1731 gpr += 2;
1732
1733 /* Synth Capture Volume + Switch */
1734 for (z = 0; z < 2; z++) {
1735 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1736 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1737 }
1738 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1739 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1740 gpr += 4;
1741
1742 /* Surround Digital Playback Volume (renamed later without Digital) */
1743 for (z = 0; z < 2; z++)
1744 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1745 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1746 gpr += 2;
1747
1748 /* Surround Capture Volume + Switch */
1749 for (z = 0; z < 2; z++) {
1750 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1751 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1752 }
1753 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1754 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1755 gpr += 4;
1756
1757 /* Center Playback Volume (renamed later without Digital) */
1758 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1759 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1760
1761 /* LFE Playback Volume + Switch (renamed later without Digital) */
1762 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1763 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1764
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001765 /* Front Playback Volume */
1766 for (z = 0; z < 2; z++)
1767 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1768 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1769 gpr += 2;
1770
1771 /* Front Capture Volume + Switch */
1772 for (z = 0; z < 2; z++) {
1773 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1774 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1775 }
1776 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
1777 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
1778 gpr += 3;
1779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 /*
1781 * Process inputs
1782 */
1783
1784 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
1785 /* AC'97 Playback Volume */
1786 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
1787 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
1788 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
1789 /* AC'97 Capture Volume */
1790 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
1791 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
1792 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
1793 }
1794
1795 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
1796 /* IEC958 TTL Playback Volume */
1797 for (z = 0; z < 2; z++)
1798 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001799 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 gpr += 2;
1801
1802 /* IEC958 TTL Capture Volume + Switch */
1803 for (z = 0; z < 2; z++) {
1804 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
1805 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1806 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001807 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
1808 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 -07001809 gpr += 4;
1810 }
1811
1812 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
1813 /* Zoom Video Playback Volume */
1814 for (z = 0; z < 2; z++)
1815 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
1816 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
1817 gpr += 2;
1818
1819 /* Zoom Video Capture Volume + Switch */
1820 for (z = 0; z < 2; z++) {
1821 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
1822 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1823 }
1824 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
1825 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
1826 gpr += 4;
1827 }
1828
1829 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
1830 /* IEC958 Optical Playback Volume */
1831 for (z = 0; z < 2; z++)
1832 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001833 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 gpr += 2;
1835
1836 /* IEC958 Optical Capture Volume */
1837 for (z = 0; z < 2; z++) {
1838 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
1839 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1840 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001841 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
1842 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 -07001843 gpr += 4;
1844 }
1845
1846 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
1847 /* Line LiveDrive Playback Volume */
1848 for (z = 0; z < 2; z++)
1849 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
1850 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
1851 gpr += 2;
1852
1853 /* Line LiveDrive Capture Volume + Switch */
1854 for (z = 0; z < 2; z++) {
1855 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
1856 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1857 }
1858 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
1859 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
1860 gpr += 4;
1861 }
1862
1863 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
1864 /* IEC958 Coax Playback Volume */
1865 for (z = 0; z < 2; z++)
1866 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001867 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 gpr += 2;
1869
1870 /* IEC958 Coax Capture Volume + Switch */
1871 for (z = 0; z < 2; z++) {
1872 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
1873 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1874 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001875 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
1876 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 -07001877 gpr += 4;
1878 }
1879
1880 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
1881 /* Line LiveDrive Playback Volume */
1882 for (z = 0; z < 2; z++)
1883 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
1884 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
1885 controls[i-1].id.index = 1;
1886 gpr += 2;
1887
1888 /* Line LiveDrive Capture Volume */
1889 for (z = 0; z < 2; z++) {
1890 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
1891 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1892 }
1893 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
1894 controls[i-1].id.index = 1;
1895 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
1896 controls[i-1].id.index = 1;
1897 gpr += 4;
1898 }
1899
1900 /*
1901 * Process tone control
1902 */
1903 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
1904 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
1905 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
1906 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
1907 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
1908 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
1909
1910 ctl = &controls[i + 0];
1911 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1912 strcpy(ctl->id.name, "Tone Control - Bass");
1913 ctl->vcount = 2;
1914 ctl->count = 10;
1915 ctl->min = 0;
1916 ctl->max = 40;
1917 ctl->value[0] = ctl->value[1] = 20;
1918 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1919 ctl = &controls[i + 1];
1920 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1921 strcpy(ctl->id.name, "Tone Control - Treble");
1922 ctl->vcount = 2;
1923 ctl->count = 10;
1924 ctl->min = 0;
1925 ctl->max = 40;
1926 ctl->value[0] = ctl->value[1] = 20;
1927 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1928
1929#define BASS_GPR 0x8c
1930#define TREBLE_GPR 0x96
1931
1932 for (z = 0; z < 5; z++) {
1933 int j;
1934 for (j = 0; j < 2; j++) {
1935 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1936 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1937 }
1938 }
1939 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
1940 int j, k, l, d;
1941 for (j = 0; j < 2; j++) { /* left/right */
1942 k = 0xa0 + (z * 8) + (j * 4);
1943 l = 0xd0 + (z * 8) + (j * 4);
1944 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1945
1946 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
1947 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
1948 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
1949 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
1950 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
1951 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
1952
1953 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
1954 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
1955 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
1956 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
1957 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
1958 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
1959
1960 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
1961
1962 if (z == 2) /* center */
1963 break;
1964 }
1965 }
1966 i += 2;
1967
1968#undef BASS_GPR
1969#undef TREBLE_GPR
1970
1971 for (z = 0; z < 6; z++) {
1972 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1973 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1974 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1975 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1976 }
1977 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
1978 gpr += 2;
1979
1980 /*
1981 * Process outputs
1982 */
1983 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
1984 /* AC'97 Playback Volume */
1985
1986 for (z = 0; z < 2; z++)
1987 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
1988 }
1989
1990 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
1991 /* IEC958 Optical Raw Playback Switch */
1992
1993 for (z = 0; z < 2; z++) {
1994 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
1995 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1996 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1997 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1998#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1999 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2000#endif
2001 }
2002
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002003 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 -07002004 gpr += 2;
2005 }
2006
2007 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2008 /* Headphone Playback Volume */
2009
2010 for (z = 0; z < 2; z++) {
2011 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2012 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2013 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2014 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2015 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2016 }
2017
2018 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2019 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2020 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2021 controls[i-1].id.index = 1;
2022 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2023 controls[i-1].id.index = 1;
2024
2025 gpr += 4;
2026 }
2027
2028 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2029 for (z = 0; z < 2; z++)
2030 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2031
2032 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2033 for (z = 0; z < 2; z++)
2034 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2035
2036 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2037#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2038 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2039 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2040#else
2041 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2042 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2043#endif
2044 }
2045
2046 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2047#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2048 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2049 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2050#else
2051 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2052 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2053#endif
2054 }
2055
2056#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2057 for (z = 0; z < 2; z++)
2058 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2059#endif
2060
2061 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2062 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2063
2064 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002065 if (emu->card_capabilities->sblive51) {
2066 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2067 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2068 *
2069 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2070 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2071 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2072 * channel. Multitrack recorders will still see the center/lfe output signal
2073 * on the second and third channels.
2074 */
2075 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2076 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2077 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2078 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2079 for (z = 4; z < 14; z++)
2080 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2081 } else {
2082 for (z = 0; z < 16; z++)
2083 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 }
Lee Revell2b637da2005-03-30 13:51:18 +02002085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
2087 if (gpr > tmp) {
2088 snd_BUG();
2089 err = -EIO;
2090 goto __err;
2091 }
2092 if (i > SND_EMU10K1_GPR_CONTROLS) {
2093 snd_BUG();
2094 err = -EIO;
2095 goto __err;
2096 }
2097
2098 /* clear remaining instruction memory */
2099 while (ptr < 0x200)
2100 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2101
2102 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2103 goto __err;
2104 seg = snd_enter_user();
2105 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002106 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 err = snd_emu10k1_icode_poke(emu, icode);
2108 snd_leave_user(seg);
2109 if (err >= 0)
2110 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2111 __err:
2112 kfree(ipcm);
2113 kfree(controls);
2114 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002115 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 kfree(icode);
2117 }
2118 return err;
2119}
2120
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002121int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
Takashi Iwai09668b42005-11-17 16:14:10 +01002123 spin_lock_init(&emu->fx8010.irq_lock);
2124 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 if (emu->audigy)
2126 return _snd_emu10k1_audigy_init_efx(emu);
2127 else
2128 return _snd_emu10k1_init_efx(emu);
2129}
2130
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002131void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132{
2133 /* stop processor */
2134 if (emu->audigy)
2135 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2136 else
2137 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2138}
2139
2140#if 0 // FIXME: who use them?
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002141int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002143 if (output < 0 || output >= 6)
2144 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2146 return 0;
2147}
2148
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002149int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002151 if (output < 0 || output >= 6)
2152 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2154 return 0;
2155}
2156#endif
2157
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002158int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159{
2160 u8 size_reg = 0;
2161
2162 /* size is in samples */
2163 if (size != 0) {
2164 size = (size - 1) >> 13;
2165
2166 while (size) {
2167 size >>= 1;
2168 size_reg++;
2169 }
2170 size = 0x2000 << size_reg;
2171 }
2172 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2173 return 0;
2174 spin_lock_irq(&emu->emu_lock);
2175 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2176 spin_unlock_irq(&emu->emu_lock);
2177 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2178 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2179 if (emu->fx8010.etram_pages.area != NULL) {
2180 snd_dma_free_pages(&emu->fx8010.etram_pages);
2181 emu->fx8010.etram_pages.area = NULL;
2182 emu->fx8010.etram_pages.bytes = 0;
2183 }
2184
2185 if (size > 0) {
2186 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2187 size * 2, &emu->fx8010.etram_pages) < 0)
2188 return -ENOMEM;
2189 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2190 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2191 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2192 spin_lock_irq(&emu->emu_lock);
2193 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002194 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196
2197 return 0;
2198}
2199
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002200static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201{
2202 return 0;
2203}
2204
2205static void copy_string(char *dst, char *src, char *null, int idx)
2206{
2207 if (src == NULL)
2208 sprintf(dst, "%s %02X", null, idx);
2209 else
2210 strcpy(dst, src);
2211}
2212
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002213static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2214 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215{
2216 char **fxbus, **extin, **extout;
2217 unsigned short fxbus_mask, extin_mask, extout_mask;
2218 int res;
2219
2220 memset(info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 info->internal_tram_size = emu->fx8010.itram_size;
2222 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2223 fxbus = fxbuses;
2224 extin = emu->audigy ? audigy_ins : creative_ins;
2225 extout = emu->audigy ? audigy_outs : creative_outs;
2226 fxbus_mask = emu->fx8010.fxbus_mask;
2227 extin_mask = emu->fx8010.extin_mask;
2228 extout_mask = emu->fx8010.extout_mask;
2229 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2230 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2231 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2232 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2233 }
2234 for (res = 16; res < 32; res++, extout++)
2235 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2236 info->gpr_controls = emu->fx8010.gpr_count;
2237 return 0;
2238}
2239
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002240static 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 -07002241{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002242 struct snd_emu10k1 *emu = hw->private_data;
2243 struct snd_emu10k1_fx8010_info *info;
2244 struct snd_emu10k1_fx8010_code *icode;
2245 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 unsigned int addr;
2247 void __user *argp = (void __user *)arg;
2248 int res;
2249
2250 switch (cmd) {
2251 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002252 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 if (!info)
2254 return -ENOMEM;
2255 if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
2256 kfree(info);
2257 return res;
2258 }
2259 if (copy_to_user(argp, info, sizeof(*info))) {
2260 kfree(info);
2261 return -EFAULT;
2262 }
2263 kfree(info);
2264 return 0;
2265 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2266 if (!capable(CAP_SYS_ADMIN))
2267 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002268 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 if (icode == NULL)
2270 return -ENOMEM;
2271 if (copy_from_user(icode, argp, sizeof(*icode))) {
2272 kfree(icode);
2273 return -EFAULT;
2274 }
2275 res = snd_emu10k1_icode_poke(emu, icode);
2276 kfree(icode);
2277 return res;
2278 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002279 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (icode == NULL)
2281 return -ENOMEM;
2282 if (copy_from_user(icode, argp, sizeof(*icode))) {
2283 kfree(icode);
2284 return -EFAULT;
2285 }
2286 res = snd_emu10k1_icode_peek(emu, icode);
2287 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2288 kfree(icode);
2289 return -EFAULT;
2290 }
2291 kfree(icode);
2292 return res;
2293 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002294 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 if (ipcm == NULL)
2296 return -ENOMEM;
2297 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2298 kfree(ipcm);
2299 return -EFAULT;
2300 }
2301 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2302 kfree(ipcm);
2303 return res;
2304 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002305 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 if (ipcm == NULL)
2307 return -ENOMEM;
2308 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2309 kfree(ipcm);
2310 return -EFAULT;
2311 }
2312 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2313 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2314 kfree(ipcm);
2315 return -EFAULT;
2316 }
2317 kfree(ipcm);
2318 return res;
2319 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2320 if (!capable(CAP_SYS_ADMIN))
2321 return -EPERM;
2322 if (get_user(addr, (unsigned int __user *)argp))
2323 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002324 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002326 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 return res;
2328 case SNDRV_EMU10K1_IOCTL_STOP:
2329 if (!capable(CAP_SYS_ADMIN))
2330 return -EPERM;
2331 if (emu->audigy)
2332 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2333 else
2334 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2335 return 0;
2336 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2337 if (!capable(CAP_SYS_ADMIN))
2338 return -EPERM;
2339 if (emu->audigy)
2340 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2341 else
2342 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2343 return 0;
2344 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2345 if (!capable(CAP_SYS_ADMIN))
2346 return -EPERM;
2347 if (emu->audigy)
2348 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2349 else
2350 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2351 udelay(10);
2352 if (emu->audigy)
2353 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2354 else
2355 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2356 return 0;
2357 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2358 if (!capable(CAP_SYS_ADMIN))
2359 return -EPERM;
2360 if (get_user(addr, (unsigned int __user *)argp))
2361 return -EFAULT;
2362 if (addr > 0x1ff)
2363 return -EINVAL;
2364 if (emu->audigy)
2365 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2366 else
2367 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2368 udelay(10);
2369 if (emu->audigy)
2370 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2371 else
2372 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2373 return 0;
2374 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2375 if (emu->audigy)
2376 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2377 else
2378 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2379 if (put_user(addr, (unsigned int __user *)argp))
2380 return -EFAULT;
2381 return 0;
2382 }
2383 return -ENOTTY;
2384}
2385
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002386static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387{
2388 return 0;
2389}
2390
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002391int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002393 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 int err;
2395
2396 if (rhwdep)
2397 *rhwdep = NULL;
2398 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2399 return err;
2400 strcpy(hw->name, "EMU10K1 (FX8010)");
2401 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2402 hw->ops.open = snd_emu10k1_fx8010_open;
2403 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2404 hw->ops.release = snd_emu10k1_fx8010_release;
2405 hw->private_data = emu;
2406 if (rhwdep)
2407 *rhwdep = hw;
2408 return 0;
2409}
Takashi Iwai09668b42005-11-17 16:14:10 +01002410
2411#ifdef CONFIG_PM
2412int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2413{
2414 int len;
2415
2416 len = emu->audigy ? 0x200 : 0x100;
2417 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2418 if (! emu->saved_gpr)
2419 return -ENOMEM;
2420 len = emu->audigy ? 0x100 : 0xa0;
2421 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2422 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2423 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2424 return -ENOMEM;
2425 len = emu->audigy ? 2 * 1024 : 2 * 512;
2426 emu->saved_icode = vmalloc(len * 4);
2427 if (! emu->saved_icode)
2428 return -ENOMEM;
2429 return 0;
2430}
2431
2432void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2433{
2434 kfree(emu->saved_gpr);
2435 kfree(emu->tram_val_saved);
2436 kfree(emu->tram_addr_saved);
2437 vfree(emu->saved_icode);
2438}
2439
2440/*
2441 * save/restore GPR, TRAM and codes
2442 */
2443void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2444{
2445 int i, len;
2446
2447 len = emu->audigy ? 0x200 : 0x100;
2448 for (i = 0; i < len; i++)
2449 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2450
2451 len = emu->audigy ? 0x100 : 0xa0;
2452 for (i = 0; i < len; i++) {
2453 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2454 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2455 if (emu->audigy) {
2456 emu->tram_addr_saved[i] >>= 12;
2457 emu->tram_addr_saved[i] |=
2458 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2459 }
2460 }
2461
2462 len = emu->audigy ? 2 * 1024 : 2 * 512;
2463 for (i = 0; i < len; i++)
2464 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2465}
2466
2467void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2468{
2469 int i, len;
2470
2471 /* set up TRAM */
2472 if (emu->fx8010.etram_pages.bytes > 0) {
2473 unsigned size, size_reg = 0;
2474 size = emu->fx8010.etram_pages.bytes / 2;
2475 size = (size - 1) >> 13;
2476 while (size) {
2477 size >>= 1;
2478 size_reg++;
2479 }
2480 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2481 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2482 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2483 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2484 }
2485
2486 if (emu->audigy)
2487 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2488 else
2489 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2490
2491 len = emu->audigy ? 0x200 : 0x100;
2492 for (i = 0; i < len; i++)
2493 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2494
2495 len = emu->audigy ? 0x100 : 0xa0;
2496 for (i = 0; i < len; i++) {
2497 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2498 emu->tram_val_saved[i]);
2499 if (! emu->audigy)
2500 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2501 emu->tram_addr_saved[i]);
2502 else {
2503 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2504 emu->tram_addr_saved[i] << 12);
2505 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2506 emu->tram_addr_saved[i] >> 20);
2507 }
2508 }
2509
2510 len = emu->audigy ? 2 * 1024 : 2 * 512;
2511 for (i = 0; i < len; i++)
2512 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2513
2514 /* start FX processor when the DSP code is updated */
2515 if (emu->audigy)
2516 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2517 else
2518 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2519}
2520#endif