blob: cd356b04078ba6d15d44905f9ea9ae7f6333ffb4 [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>
30#include <linux/delay.h>
31#include <linux/slab.h>
32#include <linux/init.h>
33#include <sound/core.h>
34#include <sound/emu10k1.h>
35
36#if 0 /* for testing purposes - digital out -> capture */
37#define EMU10K1_CAPTURE_DIGITAL_OUT
38#endif
39#if 0 /* for testing purposes - set S/PDIF to AC3 output */
40#define EMU10K1_SET_AC3_IEC958
41#endif
42#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
43#define EMU10K1_CENTER_LFE_FROM_FRONT
44#endif
45
46/*
47 * Tables
48 */
49
50static char *fxbuses[16] = {
51 /* 0x00 */ "PCM Left",
52 /* 0x01 */ "PCM Right",
53 /* 0x02 */ "PCM Surround Left",
54 /* 0x03 */ "PCM Surround Right",
55 /* 0x04 */ "MIDI Left",
56 /* 0x05 */ "MIDI Right",
57 /* 0x06 */ "Center",
58 /* 0x07 */ "LFE",
59 /* 0x08 */ NULL,
60 /* 0x09 */ NULL,
61 /* 0x0a */ NULL,
62 /* 0x0b */ NULL,
63 /* 0x0c */ "MIDI Reverb",
64 /* 0x0d */ "MIDI Chorus",
65 /* 0x0e */ NULL,
66 /* 0x0f */ NULL
67};
68
69static char *creative_ins[16] = {
70 /* 0x00 */ "AC97 Left",
71 /* 0x01 */ "AC97 Right",
72 /* 0x02 */ "TTL IEC958 Left",
73 /* 0x03 */ "TTL IEC958 Right",
74 /* 0x04 */ "Zoom Video Left",
75 /* 0x05 */ "Zoom Video Right",
76 /* 0x06 */ "Optical IEC958 Left",
77 /* 0x07 */ "Optical IEC958 Right",
78 /* 0x08 */ "Line/Mic 1 Left",
79 /* 0x09 */ "Line/Mic 1 Right",
80 /* 0x0a */ "Coaxial IEC958 Left",
81 /* 0x0b */ "Coaxial IEC958 Right",
82 /* 0x0c */ "Line/Mic 2 Left",
83 /* 0x0d */ "Line/Mic 2 Right",
84 /* 0x0e */ NULL,
85 /* 0x0f */ NULL
86};
87
88static char *audigy_ins[16] = {
89 /* 0x00 */ "AC97 Left",
90 /* 0x01 */ "AC97 Right",
91 /* 0x02 */ "Audigy CD Left",
92 /* 0x03 */ "Audigy CD Right",
93 /* 0x04 */ "Optical IEC958 Left",
94 /* 0x05 */ "Optical IEC958 Right",
95 /* 0x06 */ NULL,
96 /* 0x07 */ NULL,
97 /* 0x08 */ "Line/Mic 2 Left",
98 /* 0x09 */ "Line/Mic 2 Right",
99 /* 0x0a */ "SPDIF Left",
100 /* 0x0b */ "SPDIF Right",
101 /* 0x0c */ "Aux2 Left",
102 /* 0x0d */ "Aux2 Right",
103 /* 0x0e */ NULL,
104 /* 0x0f */ NULL
105};
106
107static char *creative_outs[32] = {
108 /* 0x00 */ "AC97 Left",
109 /* 0x01 */ "AC97 Right",
110 /* 0x02 */ "Optical IEC958 Left",
111 /* 0x03 */ "Optical IEC958 Right",
112 /* 0x04 */ "Center",
113 /* 0x05 */ "LFE",
114 /* 0x06 */ "Headphone Left",
115 /* 0x07 */ "Headphone Right",
116 /* 0x08 */ "Surround Left",
117 /* 0x09 */ "Surround Right",
118 /* 0x0a */ "PCM Capture Left",
119 /* 0x0b */ "PCM Capture Right",
120 /* 0x0c */ "MIC Capture",
121 /* 0x0d */ "AC97 Surround Left",
122 /* 0x0e */ "AC97 Surround Right",
123 /* 0x0f */ NULL,
124 /* 0x10 */ NULL,
125 /* 0x11 */ "Analog Center",
126 /* 0x12 */ "Analog LFE",
127 /* 0x13 */ NULL,
128 /* 0x14 */ NULL,
129 /* 0x15 */ NULL,
130 /* 0x16 */ NULL,
131 /* 0x17 */ NULL,
132 /* 0x18 */ NULL,
133 /* 0x19 */ NULL,
134 /* 0x1a */ NULL,
135 /* 0x1b */ NULL,
136 /* 0x1c */ NULL,
137 /* 0x1d */ NULL,
138 /* 0x1e */ NULL,
139 /* 0x1f */ NULL,
140};
141
142static char *audigy_outs[32] = {
143 /* 0x00 */ "Digital Front Left",
144 /* 0x01 */ "Digital Front Right",
145 /* 0x02 */ "Digital Center",
146 /* 0x03 */ "Digital LEF",
147 /* 0x04 */ "Headphone Left",
148 /* 0x05 */ "Headphone Right",
149 /* 0x06 */ "Digital Rear Left",
150 /* 0x07 */ "Digital Rear Right",
151 /* 0x08 */ "Front Left",
152 /* 0x09 */ "Front Right",
153 /* 0x0a */ "Center",
154 /* 0x0b */ "LFE",
155 /* 0x0c */ NULL,
156 /* 0x0d */ NULL,
157 /* 0x0e */ "Rear Left",
158 /* 0x0f */ "Rear Right",
159 /* 0x10 */ "AC97 Front Left",
160 /* 0x11 */ "AC97 Front Right",
161 /* 0x12 */ "ADC Caputre Left",
162 /* 0x13 */ "ADC Capture Right",
163 /* 0x14 */ NULL,
164 /* 0x15 */ NULL,
165 /* 0x16 */ NULL,
166 /* 0x17 */ NULL,
167 /* 0x18 */ NULL,
168 /* 0x19 */ NULL,
169 /* 0x1a */ NULL,
170 /* 0x1b */ NULL,
171 /* 0x1c */ NULL,
172 /* 0x1d */ NULL,
173 /* 0x1e */ NULL,
174 /* 0x1f */ NULL,
175};
176
177static const u32 bass_table[41][5] = {
178 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
179 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
180 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
181 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
182 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
183 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
184 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
185 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
186 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
187 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
188 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
189 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
190 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
191 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
192 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
193 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
194 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
195 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
196 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
197 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
198 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
199 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
200 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
201 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
202 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
203 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
204 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
205 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
206 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
207 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
208 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
209 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
210 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
211 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
212 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
213 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
214 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
215 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
216 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
217 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
218 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
219};
220
221static const u32 treble_table[41][5] = {
222 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
223 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
224 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
225 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
226 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
227 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
228 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
229 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
230 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
231 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
232 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
233 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
234 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
235 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
236 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
237 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
238 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
239 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
240 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
241 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
242 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
243 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
244 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
245 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
246 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
247 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
248 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
249 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
250 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
251 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
252 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
253 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
254 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
255 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
256 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
257 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
258 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
259 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
260 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
261 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
262 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
263};
264
265static const u32 db_table[101] = {
266 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
267 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
268 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
269 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
270 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
271 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
272 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
273 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
274 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
275 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
276 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
277 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
278 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
279 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
280 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
281 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
282 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
283 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
284 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
285 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
286 0x7fffffff,
287};
288
289static const u32 onoff_table[2] = {
290 0x00000000, 0x00000001
291};
292
293/*
294 */
295
296static inline mm_segment_t snd_enter_user(void)
297{
298 mm_segment_t fs = get_fs();
299 set_fs(get_ds());
300 return fs;
301}
302
303static inline void snd_leave_user(mm_segment_t fs)
304{
305 set_fs(fs);
306}
307
308/*
309 * controls
310 */
311
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100312static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100314 struct snd_emu10k1_fx8010_ctl *ctl =
315 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 if (ctl->min == 0 && ctl->max == 1)
318 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
319 else
320 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
321 uinfo->count = ctl->vcount;
322 uinfo->value.integer.min = ctl->min;
323 uinfo->value.integer.max = ctl->max;
324 return 0;
325}
326
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100327static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100329 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
330 struct snd_emu10k1_fx8010_ctl *ctl =
331 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 unsigned long flags;
333 unsigned int i;
334
335 spin_lock_irqsave(&emu->reg_lock, flags);
336 for (i = 0; i < ctl->vcount; i++)
337 ucontrol->value.integer.value[i] = ctl->value[i];
338 spin_unlock_irqrestore(&emu->reg_lock, flags);
339 return 0;
340}
341
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100342static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100344 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
345 struct snd_emu10k1_fx8010_ctl *ctl =
346 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 unsigned long flags;
348 unsigned int nval, val;
349 unsigned int i, j;
350 int change = 0;
351
352 spin_lock_irqsave(&emu->reg_lock, flags);
353 for (i = 0; i < ctl->vcount; i++) {
354 nval = ucontrol->value.integer.value[i];
355 if (nval < ctl->min)
356 nval = ctl->min;
357 if (nval > ctl->max)
358 nval = ctl->max;
359 if (nval != ctl->value[i])
360 change = 1;
361 val = ctl->value[i] = nval;
362 switch (ctl->translation) {
363 case EMU10K1_GPR_TRANSLATION_NONE:
364 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
365 break;
366 case EMU10K1_GPR_TRANSLATION_TABLE100:
367 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
368 break;
369 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200370 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
371 change = -EIO;
372 goto __error;
373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 for (j = 0; j < 5; j++)
375 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
376 break;
377 case EMU10K1_GPR_TRANSLATION_TREBLE:
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, treble_table[val][j]);
384 break;
385 case EMU10K1_GPR_TRANSLATION_ONOFF:
386 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
387 break;
388 }
389 }
390 __error:
391 spin_unlock_irqrestore(&emu->reg_lock, flags);
392 return change;
393}
394
395/*
396 * Interrupt handler
397 */
398
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100399static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100401 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
403 irq = emu->fx8010.irq_handlers;
404 while (irq) {
405 nirq = irq->next; /* irq ptr can be removed from list */
406 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
407 if (irq->handler)
408 irq->handler(emu, irq->private_data);
409 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
410 }
411 irq = nirq;
412 }
413}
414
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100415int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
416 snd_fx8010_irq_handler_t *handler,
417 unsigned char gpr_running,
418 void *private_data,
419 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100421 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 unsigned long flags;
423
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
425 if (irq == NULL)
426 return -ENOMEM;
427 irq->handler = handler;
428 irq->gpr_running = gpr_running;
429 irq->private_data = private_data;
430 irq->next = NULL;
431 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
432 if (emu->fx8010.irq_handlers == NULL) {
433 emu->fx8010.irq_handlers = irq;
434 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
435 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
436 } else {
437 irq->next = emu->fx8010.irq_handlers;
438 emu->fx8010.irq_handlers = irq;
439 }
440 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
441 if (r_irq)
442 *r_irq = irq;
443 return 0;
444}
445
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100446int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
447 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100449 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 unsigned long flags;
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
453 if ((tmp = emu->fx8010.irq_handlers) == irq) {
454 emu->fx8010.irq_handlers = tmp->next;
455 if (emu->fx8010.irq_handlers == NULL) {
456 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
457 emu->dsp_interrupt = NULL;
458 }
459 } else {
460 while (tmp && tmp->next != irq)
461 tmp = tmp->next;
462 if (tmp)
463 tmp->next = tmp->next->next;
464 }
465 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
466 kfree(irq);
467 return 0;
468}
469
470/*************************************************************************
471 * EMU10K1 effect manager
472 *************************************************************************/
473
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100474static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
475 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 u32 op, u32 r, u32 a, u32 x, u32 y)
477{
478 u_int32_t *code;
479 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200480 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 set_bit(*ptr, icode->code_valid);
482 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
483 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
484 (*ptr)++;
485}
486
487#define OP(icode, ptr, op, r, a, x, y) \
488 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
489
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100490static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
491 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 u32 op, u32 r, u32 a, u32 x, u32 y)
493{
494 u_int32_t *code;
495 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200496 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 set_bit(*ptr, icode->code_valid);
498 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
499 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
500 (*ptr)++;
501}
502
503#define A_OP(icode, ptr, op, r, a, x, y) \
504 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
505
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100506static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
508 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
509 snd_emu10k1_ptr_write(emu, pc, 0, data);
510}
511
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100512unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
514 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
515 return snd_emu10k1_ptr_read(emu, pc, 0);
516}
517
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100518static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
519 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
521 int gpr;
522 u32 val;
523
524 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
525 if (!test_bit(gpr, icode->gpr_valid))
526 continue;
527 if (get_user(val, &icode->gpr_map[gpr]))
528 return -EFAULT;
529 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
530 }
531 return 0;
532}
533
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100534static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
535 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
537 int gpr;
538 u32 val;
539
540 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
541 set_bit(gpr, icode->gpr_valid);
542 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
543 if (put_user(val, &icode->gpr_map[gpr]))
544 return -EFAULT;
545 }
546 return 0;
547}
548
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100549static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
550 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
552 int tram;
553 u32 addr, val;
554
555 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
556 if (!test_bit(tram, icode->tram_valid))
557 continue;
558 if (get_user(val, &icode->tram_data_map[tram]) ||
559 get_user(addr, &icode->tram_addr_map[tram]))
560 return -EFAULT;
561 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
562 if (!emu->audigy) {
563 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
564 } else {
565 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
566 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
567 }
568 }
569 return 0;
570}
571
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100572static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
573 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574{
575 int tram;
576 u32 val, addr;
577
578 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
579 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
580 set_bit(tram, icode->tram_valid);
581 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
582 if (!emu->audigy) {
583 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
584 } else {
585 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
586 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
587 }
588 if (put_user(val, &icode->tram_data_map[tram]) ||
589 put_user(addr, &icode->tram_addr_map[tram]))
590 return -EFAULT;
591 }
592 return 0;
593}
594
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100595static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
596 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 u32 pc, lo, hi;
599
600 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
601 if (!test_bit(pc / 2, icode->code_valid))
602 continue;
603 if (get_user(lo, &icode->code[pc + 0]) ||
604 get_user(hi, &icode->code[pc + 1]))
605 return -EFAULT;
606 snd_emu10k1_efx_write(emu, pc + 0, lo);
607 snd_emu10k1_efx_write(emu, pc + 1, hi);
608 }
609 return 0;
610}
611
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100612static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
613 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
615 u32 pc;
616
617 memset(icode->code_valid, 0, sizeof(icode->code_valid));
618 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
619 set_bit(pc / 2, icode->code_valid);
620 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
621 return -EFAULT;
622 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
623 return -EFAULT;
624 }
625 return 0;
626}
627
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100628static struct snd_emu10k1_fx8010_ctl *
629snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100631 struct snd_emu10k1_fx8010_ctl *ctl;
632 struct snd_kcontrol *kcontrol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 struct list_head *list;
634
635 list_for_each(list, &emu->fx8010.gpr_ctl) {
636 ctl = emu10k1_gpr_ctl(list);
637 kcontrol = ctl->kcontrol;
638 if (kcontrol->id.iface == id->iface &&
639 !strcmp(kcontrol->id.name, id->name) &&
640 kcontrol->id.index == id->index)
641 return ctl;
642 }
643 return NULL;
644}
645
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100646static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
647 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100650 struct snd_ctl_elem_id __user *_id;
651 struct snd_ctl_elem_id id;
652 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
653 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 int err;
655
656 for (i = 0, _id = icode->gpr_del_controls;
657 i < icode->gpr_del_control_count; i++, _id++) {
658 if (copy_from_user(&id, _id, sizeof(id)))
659 return -EFAULT;
660 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
661 return -ENOENT;
662 }
663 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
664 if (! gctl)
665 return -ENOMEM;
666 err = 0;
667 for (i = 0, _gctl = icode->gpr_add_controls;
668 i < icode->gpr_add_control_count; i++, _gctl++) {
669 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
670 err = -EFAULT;
671 goto __error;
672 }
673 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
674 continue;
675 down_read(&emu->card->controls_rwsem);
676 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
677 up_read(&emu->card->controls_rwsem);
678 err = -EEXIST;
679 goto __error;
680 }
681 up_read(&emu->card->controls_rwsem);
682 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
683 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
684 err = -EINVAL;
685 goto __error;
686 }
687 }
688 for (i = 0, _gctl = icode->gpr_list_controls;
689 i < icode->gpr_list_control_count; i++, _gctl++) {
690 /* FIXME: we need to check the WRITE access */
691 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
692 err = -EFAULT;
693 goto __error;
694 }
695 }
696 __error:
697 kfree(gctl);
698 return err;
699}
700
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100701static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100703 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100705 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 kctl->private_value = 0;
707 list_del(&ctl->list);
708 kfree(ctl);
709}
710
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100711static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
712 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100715 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
716 struct snd_emu10k1_fx8010_control_gpr *gctl;
717 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
718 struct snd_kcontrol_new knew;
719 struct snd_kcontrol *kctl;
720 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 int err = 0;
722
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100723 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
725 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
726 if (!val || !gctl || !nctl) {
727 err = -ENOMEM;
728 goto __error;
729 }
730
731 for (i = 0, _gctl = icode->gpr_add_controls;
732 i < icode->gpr_add_control_count; i++, _gctl++) {
733 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
734 err = -EFAULT;
735 goto __error;
736 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200737 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
738 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
739 err = -EINVAL;
740 goto __error;
741 }
742 if (! gctl->id.name[0]) {
743 err = -EINVAL;
744 goto __error;
745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
747 memset(&knew, 0, sizeof(knew));
748 knew.iface = gctl->id.iface;
749 knew.name = gctl->id.name;
750 knew.index = gctl->id.index;
751 knew.device = gctl->id.device;
752 knew.subdevice = gctl->id.subdevice;
753 knew.info = snd_emu10k1_gpr_ctl_info;
754 knew.get = snd_emu10k1_gpr_ctl_get;
755 knew.put = snd_emu10k1_gpr_ctl_put;
756 memset(nctl, 0, sizeof(*nctl));
757 nctl->vcount = gctl->vcount;
758 nctl->count = gctl->count;
759 for (j = 0; j < 32; j++) {
760 nctl->gpr[j] = gctl->gpr[j];
761 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
762 val->value.integer.value[j] = gctl->value[j];
763 }
764 nctl->min = gctl->min;
765 nctl->max = gctl->max;
766 nctl->translation = gctl->translation;
767 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100768 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (ctl == NULL) {
770 err = -ENOMEM;
771 goto __error;
772 }
773 knew.private_value = (unsigned long)ctl;
774 *ctl = *nctl;
775 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
776 kfree(ctl);
777 goto __error;
778 }
779 kctl->private_free = snd_emu10k1_ctl_private_free;
780 ctl->kcontrol = kctl;
781 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
782 } else {
783 /* overwrite */
784 nctl->list = ctl->list;
785 nctl->kcontrol = ctl->kcontrol;
786 *ctl = *nctl;
787 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
788 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
789 }
790 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
791 }
792 __error:
793 kfree(nctl);
794 kfree(gctl);
795 kfree(val);
796 return err;
797}
798
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100799static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
800 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100803 struct snd_ctl_elem_id id;
804 struct snd_ctl_elem_id __user *_id;
805 struct snd_emu10k1_fx8010_ctl *ctl;
806 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 for (i = 0, _id = icode->gpr_del_controls;
809 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200810 if (copy_from_user(&id, _id, sizeof(id)))
811 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 down_write(&card->controls_rwsem);
813 ctl = snd_emu10k1_look_for_ctl(emu, &id);
814 if (ctl)
815 snd_ctl_remove(card, ctl->kcontrol);
816 up_write(&card->controls_rwsem);
817 }
818 return 0;
819}
820
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100821static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
822 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
824 unsigned int i = 0, j;
825 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100826 struct snd_emu10k1_fx8010_control_gpr *gctl;
827 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
828 struct snd_emu10k1_fx8010_ctl *ctl;
829 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 struct list_head *list;
831
832 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
833 if (! gctl)
834 return -ENOMEM;
835
836 _gctl = icode->gpr_list_controls;
837 list_for_each(list, &emu->fx8010.gpr_ctl) {
838 ctl = emu10k1_gpr_ctl(list);
839 total++;
840 if (_gctl && i < icode->gpr_list_control_count) {
841 memset(gctl, 0, sizeof(*gctl));
842 id = &ctl->kcontrol->id;
843 gctl->id.iface = id->iface;
844 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
845 gctl->id.index = id->index;
846 gctl->id.device = id->device;
847 gctl->id.subdevice = id->subdevice;
848 gctl->vcount = ctl->vcount;
849 gctl->count = ctl->count;
850 for (j = 0; j < 32; j++) {
851 gctl->gpr[j] = ctl->gpr[j];
852 gctl->value[j] = ctl->value[j];
853 }
854 gctl->min = ctl->min;
855 gctl->max = ctl->max;
856 gctl->translation = ctl->translation;
857 if (copy_to_user(_gctl, gctl, sizeof(*gctl))) {
858 kfree(gctl);
859 return -EFAULT;
860 }
861 _gctl++;
862 i++;
863 }
864 }
865 icode->gpr_list_control_total = total;
866 kfree(gctl);
867 return 0;
868}
869
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100870static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
871 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
873 int err = 0;
874
875 down(&emu->fx8010.lock);
876 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
877 goto __error;
878 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
879 /* stop FX processor - this may be dangerous, but it's better to miss
880 some samples than generate wrong ones - [jk] */
881 if (emu->audigy)
882 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
883 else
884 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
885 /* ok, do the main job */
886 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
887 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
888 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
889 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
890 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
891 goto __error;
892 /* start FX processor when the DSP code is updated */
893 if (emu->audigy)
894 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
895 else
896 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
897 __error:
898 up(&emu->fx8010.lock);
899 return err;
900}
901
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100902static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
903 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904{
905 int err;
906
907 down(&emu->fx8010.lock);
908 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
909 /* ok, do the main job */
910 err = snd_emu10k1_gpr_peek(emu, icode);
911 if (err >= 0)
912 err = snd_emu10k1_tram_peek(emu, icode);
913 if (err >= 0)
914 err = snd_emu10k1_code_peek(emu, icode);
915 if (err >= 0)
916 err = snd_emu10k1_list_controls(emu, icode);
917 up(&emu->fx8010.lock);
918 return err;
919}
920
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100921static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
922 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923{
924 unsigned int i;
925 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100926 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
929 return -EINVAL;
930 if (ipcm->channels > 32)
931 return -EINVAL;
932 pcm = &emu->fx8010.pcm[ipcm->substream];
933 down(&emu->fx8010.lock);
934 spin_lock_irq(&emu->reg_lock);
935 if (pcm->opened) {
936 err = -EBUSY;
937 goto __error;
938 }
939 if (ipcm->channels == 0) { /* remove */
940 pcm->valid = 0;
941 } else {
942 /* FIXME: we need to add universal code to the PCM transfer routine */
943 if (ipcm->channels != 2) {
944 err = -EINVAL;
945 goto __error;
946 }
947 pcm->valid = 1;
948 pcm->opened = 0;
949 pcm->channels = ipcm->channels;
950 pcm->tram_start = ipcm->tram_start;
951 pcm->buffer_size = ipcm->buffer_size;
952 pcm->gpr_size = ipcm->gpr_size;
953 pcm->gpr_count = ipcm->gpr_count;
954 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
955 pcm->gpr_ptr = ipcm->gpr_ptr;
956 pcm->gpr_trigger = ipcm->gpr_trigger;
957 pcm->gpr_running = ipcm->gpr_running;
958 for (i = 0; i < pcm->channels; i++)
959 pcm->etram[i] = ipcm->etram[i];
960 }
961 __error:
962 spin_unlock_irq(&emu->reg_lock);
963 up(&emu->fx8010.lock);
964 return err;
965}
966
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100967static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
968 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 unsigned int i;
971 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100972 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
975 return -EINVAL;
976 pcm = &emu->fx8010.pcm[ipcm->substream];
977 down(&emu->fx8010.lock);
978 spin_lock_irq(&emu->reg_lock);
979 ipcm->channels = pcm->channels;
980 ipcm->tram_start = pcm->tram_start;
981 ipcm->buffer_size = pcm->buffer_size;
982 ipcm->gpr_size = pcm->gpr_size;
983 ipcm->gpr_ptr = pcm->gpr_ptr;
984 ipcm->gpr_count = pcm->gpr_count;
985 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
986 ipcm->gpr_trigger = pcm->gpr_trigger;
987 ipcm->gpr_running = pcm->gpr_running;
988 for (i = 0; i < pcm->channels; i++)
989 ipcm->etram[i] = pcm->etram[i];
990 ipcm->res1 = ipcm->res2 = 0;
991 ipcm->pad = 0;
992 spin_unlock_irq(&emu->reg_lock);
993 up(&emu->fx8010.lock);
994 return err;
995}
996
Mikael Magnussonedf8e452005-09-13 11:32:58 +0200997#define SND_EMU10K1_GPR_CONTROLS 44
998#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1000#define SND_EMU10K1_CAPTURE_CHANNELS 4
1001
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001002static void __devinit
1003snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1004 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
1006 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1007 strcpy(ctl->id.name, name);
1008 ctl->vcount = ctl->count = 1;
1009 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1010 ctl->min = 0;
1011 ctl->max = 100;
1012 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1013}
1014
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001015static void __devinit
1016snd_emu10k1_init_stereo_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 = 2;
1022 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1023 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1024 ctl->min = 0;
1025 ctl->max = 100;
1026 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1027}
1028
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001029static void __devinit
1030snd_emu10k1_init_mono_onoff_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 = 1;
1036 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1037 ctl->min = 0;
1038 ctl->max = 1;
1039 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1040}
1041
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001042static void __devinit
1043snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1044 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045{
1046 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1047 strcpy(ctl->id.name, name);
1048 ctl->vcount = ctl->count = 2;
1049 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1050 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1051 ctl->min = 0;
1052 ctl->max = 1;
1053 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1054}
1055
1056
1057/*
1058 * initial DSP configuration for Audigy
1059 */
1060
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001061static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062{
1063 int err, i, z, gpr, nctl;
1064 const int playback = 10;
1065 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1066 const int stereo_mix = capture + 2;
1067 const int tmp = 0x88;
1068 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001069 struct snd_emu10k1_fx8010_code *icode = NULL;
1070 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 u32 *gpr_map;
1072 mm_segment_t seg;
1073
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001074 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001075 (icode->gpr_map = (u_int32_t __user *)
1076 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1077 GFP_KERNEL)) == NULL ||
1078 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1079 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 err = -ENOMEM;
1081 goto __err;
1082 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001083 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
1085 icode->tram_data_map = icode->gpr_map + 512;
1086 icode->tram_addr_map = icode->tram_data_map + 256;
1087 icode->code = icode->tram_addr_map + 256;
1088
1089 /* clear free GPRs */
1090 for (i = 0; i < 512; i++)
1091 set_bit(i, icode->gpr_valid);
1092
1093 /* clear TRAM data & address lines */
1094 for (i = 0; i < 256; i++)
1095 set_bit(i, icode->tram_valid);
1096
1097 strcpy(icode->name, "Audigy DSP code for ALSA");
1098 ptr = 0;
1099 nctl = 0;
1100 gpr = stereo_mix + 10;
1101
1102 /* stop FX processor */
1103 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1104
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001105#if 0
1106 /* FIX: jcd test */
1107 for (z = 0; z < 80; z=z+2) {
1108 A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
1109 A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
1110 }
1111#endif /* jcd test */
1112#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 /* PCM front Playback Volume (independent from stereo mix) */
1114 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1115 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1116 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1117 gpr += 2;
1118
1119 /* PCM Surround Playback (independent from stereo mix) */
1120 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1121 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1122 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1123 gpr += 2;
1124
1125 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001126 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1128 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1129 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1130 gpr += 2;
1131 }
1132
1133 /* PCM Center Playback (independent from stereo mix) */
1134 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1135 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1136 gpr++;
1137
1138 /* PCM LFE Playback (independent from stereo mix) */
1139 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1140 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1141 gpr++;
1142
1143 /*
1144 * Stereo Mix
1145 */
1146 /* Wave (PCM) Playback Volume (will be renamed later) */
1147 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1148 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1149 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1150 gpr += 2;
1151
1152 /* Synth Playback */
1153 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1154 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1155 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1156 gpr += 2;
1157
1158 /* Wave (PCM) Capture */
1159 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1160 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1161 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1162 gpr += 2;
1163
1164 /* Synth Capture */
1165 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1166 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1167 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1168 gpr += 2;
1169
1170 /*
1171 * inputs
1172 */
1173#define A_ADD_VOLUME_IN(var,vol,input) \
1174A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1175
1176 /* AC'97 Playback Volume - used only for mic (renamed later) */
1177 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1178 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1179 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1180 gpr += 2;
1181 /* AC'97 Capture Volume - used only for mic */
1182 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1183 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1184 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1185 gpr += 2;
1186
1187 /* mic capture buffer */
1188 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1189
1190 /* Audigy CD Playback Volume */
1191 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1192 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1193 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001194 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 gpr, 0);
1196 gpr += 2;
1197 /* Audigy CD Capture Volume */
1198 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1199 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1200 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001201 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 gpr, 0);
1203 gpr += 2;
1204
1205 /* Optical SPDIF Playback Volume */
1206 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1207 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001208 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 gpr += 2;
1210 /* Optical SPDIF Capture Volume */
1211 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1212 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001213 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 gpr += 2;
1215
1216 /* Line2 Playback Volume */
1217 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1218 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1219 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001220 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 gpr, 0);
1222 gpr += 2;
1223 /* Line2 Capture Volume */
1224 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1225 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1226 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001227 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 gpr, 0);
1229 gpr += 2;
1230
1231 /* Philips ADC Playback Volume */
1232 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1233 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1234 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1235 gpr += 2;
1236 /* Philips ADC Capture Volume */
1237 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1238 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1239 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1240 gpr += 2;
1241
1242 /* Aux2 Playback Volume */
1243 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1244 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1245 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001246 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 gpr, 0);
1248 gpr += 2;
1249 /* Aux2 Capture Volume */
1250 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1251 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1252 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001253 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 gpr, 0);
1255 gpr += 2;
1256
1257 /* Stereo Mix Front Playback Volume */
1258 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1259 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1260 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1261 gpr += 2;
1262
1263 /* Stereo Mix Surround Playback */
1264 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1265 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1266 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1267 gpr += 2;
1268
1269 /* Stereo Mix Center Playback */
1270 /* Center = sub = Left/2 + Right/2 */
1271 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1272 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1273 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1274 gpr++;
1275
1276 /* Stereo Mix LFE Playback */
1277 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1278 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1279 gpr++;
1280
Lee Revell2b637da2005-03-30 13:51:18 +02001281 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 /* Stereo Mix Side Playback */
1283 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1284 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1285 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1286 gpr += 2;
1287 }
1288
1289 /*
1290 * outputs
1291 */
1292#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1293#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1294 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1295
1296#define _A_SWITCH(icode, ptr, dst, src, sw) \
1297 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1298#define A_SWITCH(icode, ptr, dst, src, sw) \
1299 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1300#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1301 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1302#define A_SWITCH_NEG(icode, ptr, dst, src) \
1303 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1304
1305
1306 /*
1307 * Process tone control
1308 */
1309 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1310 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1311 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 */
1312 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 */
1313 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1314 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 +02001315 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 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 */
1317 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 */
1318 }
1319
1320
1321 ctl = &controls[nctl + 0];
1322 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1323 strcpy(ctl->id.name, "Tone Control - Bass");
1324 ctl->vcount = 2;
1325 ctl->count = 10;
1326 ctl->min = 0;
1327 ctl->max = 40;
1328 ctl->value[0] = ctl->value[1] = 20;
1329 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1330 ctl = &controls[nctl + 1];
1331 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1332 strcpy(ctl->id.name, "Tone Control - Treble");
1333 ctl->vcount = 2;
1334 ctl->count = 10;
1335 ctl->min = 0;
1336 ctl->max = 40;
1337 ctl->value[0] = ctl->value[1] = 20;
1338 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1339
1340#define BASS_GPR 0x8c
1341#define TREBLE_GPR 0x96
1342
1343 for (z = 0; z < 5; z++) {
1344 int j;
1345 for (j = 0; j < 2; j++) {
1346 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1347 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1348 }
1349 }
1350 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1351 int j, k, l, d;
1352 for (j = 0; j < 2; j++) { /* left/right */
1353 k = 0xb0 + (z * 8) + (j * 4);
1354 l = 0xe0 + (z * 8) + (j * 4);
1355 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1356
1357 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1358 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1359 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1360 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1361 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1362 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1363
1364 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1365 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1366 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1367 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1368 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1369 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1370
1371 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1372
1373 if (z == 2) /* center */
1374 break;
1375 }
1376 }
1377 nctl += 2;
1378
1379#undef BASS_GPR
1380#undef TREBLE_GPR
1381
1382 for (z = 0; z < 8; z++) {
1383 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1384 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1385 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1386 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1387 }
1388 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1389 gpr += 2;
1390
1391 /* Master volume (will be renamed later) */
1392 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));
1393 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));
1394 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));
1395 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));
1396 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));
1397 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));
1398 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));
1399 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));
1400 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1401 gpr += 2;
1402
1403 /* analog speakers */
1404 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1405 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1406 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1407 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001408 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1410
1411 /* headphone */
1412 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1413
1414 /* digital outputs */
1415 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
1416
1417 /* IEC958 Optical Raw Playback Switch */
1418 gpr_map[gpr++] = 0;
1419 gpr_map[gpr++] = 0x1008;
1420 gpr_map[gpr++] = 0xffff0000;
1421 for (z = 0; z < 2; z++) {
1422 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1423 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1424 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1425 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1426 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1427 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1428 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1429 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1430 /* 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 +02001431 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1433 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1434 } else {
1435 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1436 }
1437 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001438 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 -07001439 gpr += 2;
1440
1441 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1442 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1443 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1444
1445 /* ADC buffer */
1446#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1447 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1448#else
1449 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1450 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1451#endif
1452
1453 /* EFX capture - capture the 16 EXTINs */
1454 for (z = 0; z < 16; z++) {
1455 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1456 }
1457
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001458#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 /*
1460 * ok, set up done..
1461 */
1462
1463 if (gpr > tmp) {
1464 snd_BUG();
1465 err = -EIO;
1466 goto __err;
1467 }
1468 /* clear remaining instruction memory */
1469 while (ptr < 0x400)
1470 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1471
1472 seg = snd_enter_user();
1473 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001474 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 err = snd_emu10k1_icode_poke(emu, icode);
1476 snd_leave_user(seg);
1477
1478 __err:
1479 kfree(controls);
1480 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001481 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 kfree(icode);
1483 }
1484 return err;
1485}
1486
1487
1488/*
1489 * initial DSP configuration for Emu10k1
1490 */
1491
1492/* when volume = max, then copy only to avoid volume modification */
1493/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001494static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1497 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1498 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1499 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1500}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001501static 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 -07001502{
1503 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1504 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1505 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1506 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1507 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1508}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001509static 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 -07001510{
1511 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1512 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1513 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1514 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1515 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1516}
1517
1518#define VOLUME(icode, ptr, dst, src, vol) \
1519 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1520#define VOLUME_IN(icode, ptr, dst, src, vol) \
1521 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1522#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1523 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1524#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1525 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1526#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1527 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1528#define _SWITCH(icode, ptr, dst, src, sw) \
1529 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1530#define SWITCH(icode, ptr, dst, src, sw) \
1531 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1532#define SWITCH_IN(icode, ptr, dst, src, sw) \
1533 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1534#define _SWITCH_NEG(icode, ptr, dst, src) \
1535 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1536#define SWITCH_NEG(icode, ptr, dst, src) \
1537 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1538
1539
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001540static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
1542 int err, i, z, gpr, tmp, playback, capture;
1543 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001544 struct snd_emu10k1_fx8010_code *icode;
1545 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1546 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 u32 *gpr_map;
1548 mm_segment_t seg;
1549
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001550 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001552 if ((icode->gpr_map = (u_int32_t __user *)
1553 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1554 GFP_KERNEL)) == NULL ||
1555 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1556 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1557 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001558 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 err = -ENOMEM;
1560 goto __err;
1561 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001562 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
1564 icode->tram_data_map = icode->gpr_map + 256;
1565 icode->tram_addr_map = icode->tram_data_map + 160;
1566 icode->code = icode->tram_addr_map + 160;
1567
1568 /* clear free GPRs */
1569 for (i = 0; i < 256; i++)
1570 set_bit(i, icode->gpr_valid);
1571
1572 /* clear TRAM data & address lines */
1573 for (i = 0; i < 160; i++)
1574 set_bit(i, icode->tram_valid);
1575
1576 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1577 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001578 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 playback = SND_EMU10K1_INPUTS;
1580 /* we have 6 playback channels and tone control doubles */
1581 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1582 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1583 tmp = 0x88; /* we need 4 temporary GPR */
1584 /* from 0x8c to 0xff is the area for tone control */
1585
1586 /* stop FX processor */
1587 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1588
1589 /*
1590 * Process FX Buses
1591 */
1592 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1593 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1594 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1595 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1596 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1597 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1598 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1599 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1600 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1601 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001602 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1603 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 /* Raw S/PDIF PCM */
1606 ipcm->substream = 0;
1607 ipcm->channels = 2;
1608 ipcm->tram_start = 0;
1609 ipcm->buffer_size = (64 * 1024) / 2;
1610 ipcm->gpr_size = gpr++;
1611 ipcm->gpr_ptr = gpr++;
1612 ipcm->gpr_count = gpr++;
1613 ipcm->gpr_tmpcount = gpr++;
1614 ipcm->gpr_trigger = gpr++;
1615 ipcm->gpr_running = gpr++;
1616 ipcm->etram[0] = 0;
1617 ipcm->etram[1] = 1;
1618
1619 gpr_map[gpr + 0] = 0xfffff000;
1620 gpr_map[gpr + 1] = 0xffff0000;
1621 gpr_map[gpr + 2] = 0x70000000;
1622 gpr_map[gpr + 3] = 0x00000007;
1623 gpr_map[gpr + 4] = 0x001f << 11;
1624 gpr_map[gpr + 5] = 0x001c << 11;
1625 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1626 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1627 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1628 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1629 gpr_map[gpr + 10] = 1<<11;
1630 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1631 gpr_map[gpr + 12] = 0;
1632
1633 /* if the trigger flag is not set, skip */
1634 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1635 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1636 /* if the running flag is set, we're running */
1637 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1638 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1639 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1640 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1641 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1642 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1643 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1644
1645 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1646 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1647 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1648 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1649
1650 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1651 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1652 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1653 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1654 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1655
1656 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1657 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1658 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1659 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1660 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1661
1662 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1663 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1664 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1665 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1666 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1667
1668 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1669 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1670 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1671 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1672 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1673
1674 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1675 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1676
1677 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1678 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1679
1680 /* 24: */
1681 gpr += 13;
1682
1683 /* Wave Playback Volume */
1684 for (z = 0; z < 2; z++)
1685 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1686 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1687 gpr += 2;
1688
1689 /* Wave Surround Playback Volume */
1690 for (z = 0; z < 2; z++)
1691 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1692 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1693 gpr += 2;
1694
1695 /* Wave Center/LFE Playback Volume */
1696 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1697 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1698 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1699 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1700 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1701 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1702
1703 /* Wave Capture Volume + Switch */
1704 for (z = 0; z < 2; z++) {
1705 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1706 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1707 }
1708 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1709 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1710 gpr += 4;
1711
1712 /* Synth Playback Volume */
1713 for (z = 0; z < 2; z++)
1714 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1715 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1716 gpr += 2;
1717
1718 /* Synth Capture Volume + Switch */
1719 for (z = 0; z < 2; z++) {
1720 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1721 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1722 }
1723 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1724 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1725 gpr += 4;
1726
1727 /* Surround Digital Playback Volume (renamed later without Digital) */
1728 for (z = 0; z < 2; z++)
1729 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1730 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1731 gpr += 2;
1732
1733 /* Surround Capture Volume + Switch */
1734 for (z = 0; z < 2; z++) {
1735 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1736 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1737 }
1738 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1739 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1740 gpr += 4;
1741
1742 /* Center Playback Volume (renamed later without Digital) */
1743 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1744 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1745
1746 /* LFE Playback Volume + Switch (renamed later without Digital) */
1747 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1748 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1749
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001750 /* Front Playback Volume */
1751 for (z = 0; z < 2; z++)
1752 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1753 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1754 gpr += 2;
1755
1756 /* Front Capture Volume + Switch */
1757 for (z = 0; z < 2; z++) {
1758 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1759 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1760 }
1761 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
1762 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
1763 gpr += 3;
1764
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 /*
1766 * Process inputs
1767 */
1768
1769 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
1770 /* AC'97 Playback Volume */
1771 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
1772 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
1773 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
1774 /* AC'97 Capture Volume */
1775 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
1776 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
1777 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
1778 }
1779
1780 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
1781 /* IEC958 TTL Playback Volume */
1782 for (z = 0; z < 2; z++)
1783 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001784 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 gpr += 2;
1786
1787 /* IEC958 TTL Capture Volume + Switch */
1788 for (z = 0; z < 2; z++) {
1789 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
1790 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1791 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001792 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
1793 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 -07001794 gpr += 4;
1795 }
1796
1797 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
1798 /* Zoom Video Playback Volume */
1799 for (z = 0; z < 2; z++)
1800 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
1801 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
1802 gpr += 2;
1803
1804 /* Zoom Video Capture Volume + Switch */
1805 for (z = 0; z < 2; z++) {
1806 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
1807 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1808 }
1809 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
1810 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
1811 gpr += 4;
1812 }
1813
1814 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
1815 /* IEC958 Optical Playback Volume */
1816 for (z = 0; z < 2; z++)
1817 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001818 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 gpr += 2;
1820
1821 /* IEC958 Optical Capture Volume */
1822 for (z = 0; z < 2; z++) {
1823 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
1824 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1825 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001826 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
1827 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 -07001828 gpr += 4;
1829 }
1830
1831 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
1832 /* Line LiveDrive Playback Volume */
1833 for (z = 0; z < 2; z++)
1834 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
1835 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
1836 gpr += 2;
1837
1838 /* Line LiveDrive Capture Volume + Switch */
1839 for (z = 0; z < 2; z++) {
1840 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
1841 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1842 }
1843 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
1844 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
1845 gpr += 4;
1846 }
1847
1848 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
1849 /* IEC958 Coax Playback Volume */
1850 for (z = 0; z < 2; z++)
1851 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001852 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 gpr += 2;
1854
1855 /* IEC958 Coax Capture Volume + Switch */
1856 for (z = 0; z < 2; z++) {
1857 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
1858 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1859 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001860 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
1861 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 -07001862 gpr += 4;
1863 }
1864
1865 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
1866 /* Line LiveDrive Playback Volume */
1867 for (z = 0; z < 2; z++)
1868 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
1869 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
1870 controls[i-1].id.index = 1;
1871 gpr += 2;
1872
1873 /* Line LiveDrive Capture Volume */
1874 for (z = 0; z < 2; z++) {
1875 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
1876 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1877 }
1878 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
1879 controls[i-1].id.index = 1;
1880 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
1881 controls[i-1].id.index = 1;
1882 gpr += 4;
1883 }
1884
1885 /*
1886 * Process tone control
1887 */
1888 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
1889 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
1890 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
1891 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
1892 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
1893 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
1894
1895 ctl = &controls[i + 0];
1896 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1897 strcpy(ctl->id.name, "Tone Control - Bass");
1898 ctl->vcount = 2;
1899 ctl->count = 10;
1900 ctl->min = 0;
1901 ctl->max = 40;
1902 ctl->value[0] = ctl->value[1] = 20;
1903 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1904 ctl = &controls[i + 1];
1905 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1906 strcpy(ctl->id.name, "Tone Control - Treble");
1907 ctl->vcount = 2;
1908 ctl->count = 10;
1909 ctl->min = 0;
1910 ctl->max = 40;
1911 ctl->value[0] = ctl->value[1] = 20;
1912 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1913
1914#define BASS_GPR 0x8c
1915#define TREBLE_GPR 0x96
1916
1917 for (z = 0; z < 5; z++) {
1918 int j;
1919 for (j = 0; j < 2; j++) {
1920 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1921 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1922 }
1923 }
1924 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
1925 int j, k, l, d;
1926 for (j = 0; j < 2; j++) { /* left/right */
1927 k = 0xa0 + (z * 8) + (j * 4);
1928 l = 0xd0 + (z * 8) + (j * 4);
1929 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1930
1931 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
1932 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
1933 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
1934 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
1935 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
1936 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
1937
1938 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
1939 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
1940 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
1941 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
1942 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
1943 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
1944
1945 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
1946
1947 if (z == 2) /* center */
1948 break;
1949 }
1950 }
1951 i += 2;
1952
1953#undef BASS_GPR
1954#undef TREBLE_GPR
1955
1956 for (z = 0; z < 6; z++) {
1957 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1958 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1959 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1960 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1961 }
1962 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
1963 gpr += 2;
1964
1965 /*
1966 * Process outputs
1967 */
1968 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
1969 /* AC'97 Playback Volume */
1970
1971 for (z = 0; z < 2; z++)
1972 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
1973 }
1974
1975 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
1976 /* IEC958 Optical Raw Playback Switch */
1977
1978 for (z = 0; z < 2; z++) {
1979 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
1980 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1981 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1982 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1983#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1984 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
1985#endif
1986 }
1987
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001988 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 -07001989 gpr += 2;
1990 }
1991
1992 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
1993 /* Headphone Playback Volume */
1994
1995 for (z = 0; z < 2; z++) {
1996 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
1997 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
1998 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1999 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2000 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2001 }
2002
2003 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2004 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2005 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2006 controls[i-1].id.index = 1;
2007 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2008 controls[i-1].id.index = 1;
2009
2010 gpr += 4;
2011 }
2012
2013 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2014 for (z = 0; z < 2; z++)
2015 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2016
2017 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2018 for (z = 0; z < 2; z++)
2019 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2020
2021 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2022#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2023 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2024 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2025#else
2026 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2027 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2028#endif
2029 }
2030
2031 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2032#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2033 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2034 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2035#else
2036 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2037 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2038#endif
2039 }
2040
2041#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2042 for (z = 0; z < 2; z++)
2043 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2044#endif
2045
2046 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2047 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2048
2049 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002050 if (emu->card_capabilities->sblive51) {
2051 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2052 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2053 *
2054 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2055 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2056 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2057 * channel. Multitrack recorders will still see the center/lfe output signal
2058 * on the second and third channels.
2059 */
2060 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2061 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2062 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2063 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2064 for (z = 4; z < 14; z++)
2065 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2066 } else {
2067 for (z = 0; z < 16; z++)
2068 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 }
Lee Revell2b637da2005-03-30 13:51:18 +02002070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 if (gpr > tmp) {
2073 snd_BUG();
2074 err = -EIO;
2075 goto __err;
2076 }
2077 if (i > SND_EMU10K1_GPR_CONTROLS) {
2078 snd_BUG();
2079 err = -EIO;
2080 goto __err;
2081 }
2082
2083 /* clear remaining instruction memory */
2084 while (ptr < 0x200)
2085 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2086
2087 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2088 goto __err;
2089 seg = snd_enter_user();
2090 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002091 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 err = snd_emu10k1_icode_poke(emu, icode);
2093 snd_leave_user(seg);
2094 if (err >= 0)
2095 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2096 __err:
2097 kfree(ipcm);
2098 kfree(controls);
2099 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002100 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 kfree(icode);
2102 }
2103 return err;
2104}
2105
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002106int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
Takashi Iwai09668b42005-11-17 16:14:10 +01002108 spin_lock_init(&emu->fx8010.irq_lock);
2109 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 if (emu->audigy)
2111 return _snd_emu10k1_audigy_init_efx(emu);
2112 else
2113 return _snd_emu10k1_init_efx(emu);
2114}
2115
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002116void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117{
2118 /* stop processor */
2119 if (emu->audigy)
2120 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2121 else
2122 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2123}
2124
2125#if 0 // FIXME: who use them?
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002126int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002128 if (output < 0 || output >= 6)
2129 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2131 return 0;
2132}
2133
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002134int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002136 if (output < 0 || output >= 6)
2137 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2139 return 0;
2140}
2141#endif
2142
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002143int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144{
2145 u8 size_reg = 0;
2146
2147 /* size is in samples */
2148 if (size != 0) {
2149 size = (size - 1) >> 13;
2150
2151 while (size) {
2152 size >>= 1;
2153 size_reg++;
2154 }
2155 size = 0x2000 << size_reg;
2156 }
2157 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2158 return 0;
2159 spin_lock_irq(&emu->emu_lock);
2160 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2161 spin_unlock_irq(&emu->emu_lock);
2162 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2163 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2164 if (emu->fx8010.etram_pages.area != NULL) {
2165 snd_dma_free_pages(&emu->fx8010.etram_pages);
2166 emu->fx8010.etram_pages.area = NULL;
2167 emu->fx8010.etram_pages.bytes = 0;
2168 }
2169
2170 if (size > 0) {
2171 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2172 size * 2, &emu->fx8010.etram_pages) < 0)
2173 return -ENOMEM;
2174 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2175 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2176 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2177 spin_lock_irq(&emu->emu_lock);
2178 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002179 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181
2182 return 0;
2183}
2184
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002185static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186{
2187 return 0;
2188}
2189
2190static void copy_string(char *dst, char *src, char *null, int idx)
2191{
2192 if (src == NULL)
2193 sprintf(dst, "%s %02X", null, idx);
2194 else
2195 strcpy(dst, src);
2196}
2197
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002198static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2199 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200{
2201 char **fxbus, **extin, **extout;
2202 unsigned short fxbus_mask, extin_mask, extout_mask;
2203 int res;
2204
2205 memset(info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 info->internal_tram_size = emu->fx8010.itram_size;
2207 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2208 fxbus = fxbuses;
2209 extin = emu->audigy ? audigy_ins : creative_ins;
2210 extout = emu->audigy ? audigy_outs : creative_outs;
2211 fxbus_mask = emu->fx8010.fxbus_mask;
2212 extin_mask = emu->fx8010.extin_mask;
2213 extout_mask = emu->fx8010.extout_mask;
2214 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2215 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2216 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2217 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2218 }
2219 for (res = 16; res < 32; res++, extout++)
2220 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2221 info->gpr_controls = emu->fx8010.gpr_count;
2222 return 0;
2223}
2224
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002225static 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 -07002226{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002227 struct snd_emu10k1 *emu = hw->private_data;
2228 struct snd_emu10k1_fx8010_info *info;
2229 struct snd_emu10k1_fx8010_code *icode;
2230 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 unsigned int addr;
2232 void __user *argp = (void __user *)arg;
2233 int res;
2234
2235 switch (cmd) {
2236 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002237 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if (!info)
2239 return -ENOMEM;
2240 if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
2241 kfree(info);
2242 return res;
2243 }
2244 if (copy_to_user(argp, info, sizeof(*info))) {
2245 kfree(info);
2246 return -EFAULT;
2247 }
2248 kfree(info);
2249 return 0;
2250 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2251 if (!capable(CAP_SYS_ADMIN))
2252 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002253 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 if (icode == NULL)
2255 return -ENOMEM;
2256 if (copy_from_user(icode, argp, sizeof(*icode))) {
2257 kfree(icode);
2258 return -EFAULT;
2259 }
2260 res = snd_emu10k1_icode_poke(emu, icode);
2261 kfree(icode);
2262 return res;
2263 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002264 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 if (icode == NULL)
2266 return -ENOMEM;
2267 if (copy_from_user(icode, argp, sizeof(*icode))) {
2268 kfree(icode);
2269 return -EFAULT;
2270 }
2271 res = snd_emu10k1_icode_peek(emu, icode);
2272 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2273 kfree(icode);
2274 return -EFAULT;
2275 }
2276 kfree(icode);
2277 return res;
2278 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002279 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (ipcm == NULL)
2281 return -ENOMEM;
2282 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2283 kfree(ipcm);
2284 return -EFAULT;
2285 }
2286 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2287 kfree(ipcm);
2288 return res;
2289 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002290 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 if (ipcm == NULL)
2292 return -ENOMEM;
2293 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2294 kfree(ipcm);
2295 return -EFAULT;
2296 }
2297 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2298 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2299 kfree(ipcm);
2300 return -EFAULT;
2301 }
2302 kfree(ipcm);
2303 return res;
2304 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2305 if (!capable(CAP_SYS_ADMIN))
2306 return -EPERM;
2307 if (get_user(addr, (unsigned int __user *)argp))
2308 return -EFAULT;
2309 down(&emu->fx8010.lock);
2310 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
2311 up(&emu->fx8010.lock);
2312 return res;
2313 case SNDRV_EMU10K1_IOCTL_STOP:
2314 if (!capable(CAP_SYS_ADMIN))
2315 return -EPERM;
2316 if (emu->audigy)
2317 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2318 else
2319 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2320 return 0;
2321 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2322 if (!capable(CAP_SYS_ADMIN))
2323 return -EPERM;
2324 if (emu->audigy)
2325 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2326 else
2327 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2328 return 0;
2329 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2330 if (!capable(CAP_SYS_ADMIN))
2331 return -EPERM;
2332 if (emu->audigy)
2333 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2334 else
2335 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2336 udelay(10);
2337 if (emu->audigy)
2338 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2339 else
2340 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2341 return 0;
2342 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2343 if (!capable(CAP_SYS_ADMIN))
2344 return -EPERM;
2345 if (get_user(addr, (unsigned int __user *)argp))
2346 return -EFAULT;
2347 if (addr > 0x1ff)
2348 return -EINVAL;
2349 if (emu->audigy)
2350 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2351 else
2352 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2353 udelay(10);
2354 if (emu->audigy)
2355 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2356 else
2357 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2358 return 0;
2359 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2360 if (emu->audigy)
2361 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2362 else
2363 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2364 if (put_user(addr, (unsigned int __user *)argp))
2365 return -EFAULT;
2366 return 0;
2367 }
2368 return -ENOTTY;
2369}
2370
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002371static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372{
2373 return 0;
2374}
2375
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002376int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002378 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 int err;
2380
2381 if (rhwdep)
2382 *rhwdep = NULL;
2383 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2384 return err;
2385 strcpy(hw->name, "EMU10K1 (FX8010)");
2386 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2387 hw->ops.open = snd_emu10k1_fx8010_open;
2388 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2389 hw->ops.release = snd_emu10k1_fx8010_release;
2390 hw->private_data = emu;
2391 if (rhwdep)
2392 *rhwdep = hw;
2393 return 0;
2394}
Takashi Iwai09668b42005-11-17 16:14:10 +01002395
2396#ifdef CONFIG_PM
2397int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2398{
2399 int len;
2400
2401 len = emu->audigy ? 0x200 : 0x100;
2402 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2403 if (! emu->saved_gpr)
2404 return -ENOMEM;
2405 len = emu->audigy ? 0x100 : 0xa0;
2406 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2407 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2408 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2409 return -ENOMEM;
2410 len = emu->audigy ? 2 * 1024 : 2 * 512;
2411 emu->saved_icode = vmalloc(len * 4);
2412 if (! emu->saved_icode)
2413 return -ENOMEM;
2414 return 0;
2415}
2416
2417void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2418{
2419 kfree(emu->saved_gpr);
2420 kfree(emu->tram_val_saved);
2421 kfree(emu->tram_addr_saved);
2422 vfree(emu->saved_icode);
2423}
2424
2425/*
2426 * save/restore GPR, TRAM and codes
2427 */
2428void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2429{
2430 int i, len;
2431
2432 len = emu->audigy ? 0x200 : 0x100;
2433 for (i = 0; i < len; i++)
2434 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2435
2436 len = emu->audigy ? 0x100 : 0xa0;
2437 for (i = 0; i < len; i++) {
2438 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2439 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2440 if (emu->audigy) {
2441 emu->tram_addr_saved[i] >>= 12;
2442 emu->tram_addr_saved[i] |=
2443 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2444 }
2445 }
2446
2447 len = emu->audigy ? 2 * 1024 : 2 * 512;
2448 for (i = 0; i < len; i++)
2449 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2450}
2451
2452void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2453{
2454 int i, len;
2455
2456 /* set up TRAM */
2457 if (emu->fx8010.etram_pages.bytes > 0) {
2458 unsigned size, size_reg = 0;
2459 size = emu->fx8010.etram_pages.bytes / 2;
2460 size = (size - 1) >> 13;
2461 while (size) {
2462 size >>= 1;
2463 size_reg++;
2464 }
2465 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2466 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2467 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2468 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2469 }
2470
2471 if (emu->audigy)
2472 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2473 else
2474 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2475
2476 len = emu->audigy ? 0x200 : 0x100;
2477 for (i = 0; i < len; i++)
2478 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2479
2480 len = emu->audigy ? 0x100 : 0xa0;
2481 for (i = 0; i < len; i++) {
2482 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2483 emu->tram_val_saved[i]);
2484 if (! emu->audigy)
2485 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2486 emu->tram_addr_saved[i]);
2487 else {
2488 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2489 emu->tram_addr_saved[i] << 12);
2490 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2491 emu->tram_addr_saved[i] >> 20);
2492 }
2493 }
2494
2495 len = emu->audigy ? 2 * 1024 : 2 * 512;
2496 for (i = 0; i < len; i++)
2497 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2498
2499 /* start FX processor when the DSP code is updated */
2500 if (emu->audigy)
2501 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2502 else
2503 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2504}
2505#endif