blob: c02012cccd8ee767e0823539a6f287d2626c5362 [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 *
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01006 * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
7 * Added EMU 1010 support.
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * BUGS:
10 * --
11 *
12 * TODO:
13 * --
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 */
30
31#include <sound/driver.h>
32#include <linux/pci.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/delay.h>
35#include <linux/slab.h>
Andreas Schwabbd01e7b2005-12-05 15:12:20 +010036#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/init.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010038#include <linux/mutex.h>
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <sound/core.h>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010041#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <sound/emu10k1.h>
43
44#if 0 /* for testing purposes - digital out -> capture */
45#define EMU10K1_CAPTURE_DIGITAL_OUT
46#endif
47#if 0 /* for testing purposes - set S/PDIF to AC3 output */
48#define EMU10K1_SET_AC3_IEC958
49#endif
50#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
51#define EMU10K1_CENTER_LFE_FROM_FRONT
52#endif
53
54/*
55 * Tables
56 */
57
58static char *fxbuses[16] = {
59 /* 0x00 */ "PCM Left",
60 /* 0x01 */ "PCM Right",
61 /* 0x02 */ "PCM Surround Left",
62 /* 0x03 */ "PCM Surround Right",
63 /* 0x04 */ "MIDI Left",
64 /* 0x05 */ "MIDI Right",
65 /* 0x06 */ "Center",
66 /* 0x07 */ "LFE",
67 /* 0x08 */ NULL,
68 /* 0x09 */ NULL,
69 /* 0x0a */ NULL,
70 /* 0x0b */ NULL,
71 /* 0x0c */ "MIDI Reverb",
72 /* 0x0d */ "MIDI Chorus",
73 /* 0x0e */ NULL,
74 /* 0x0f */ NULL
75};
76
77static char *creative_ins[16] = {
78 /* 0x00 */ "AC97 Left",
79 /* 0x01 */ "AC97 Right",
80 /* 0x02 */ "TTL IEC958 Left",
81 /* 0x03 */ "TTL IEC958 Right",
82 /* 0x04 */ "Zoom Video Left",
83 /* 0x05 */ "Zoom Video Right",
84 /* 0x06 */ "Optical IEC958 Left",
85 /* 0x07 */ "Optical IEC958 Right",
86 /* 0x08 */ "Line/Mic 1 Left",
87 /* 0x09 */ "Line/Mic 1 Right",
88 /* 0x0a */ "Coaxial IEC958 Left",
89 /* 0x0b */ "Coaxial IEC958 Right",
90 /* 0x0c */ "Line/Mic 2 Left",
91 /* 0x0d */ "Line/Mic 2 Right",
92 /* 0x0e */ NULL,
93 /* 0x0f */ NULL
94};
95
96static char *audigy_ins[16] = {
97 /* 0x00 */ "AC97 Left",
98 /* 0x01 */ "AC97 Right",
99 /* 0x02 */ "Audigy CD Left",
100 /* 0x03 */ "Audigy CD Right",
101 /* 0x04 */ "Optical IEC958 Left",
102 /* 0x05 */ "Optical IEC958 Right",
103 /* 0x06 */ NULL,
104 /* 0x07 */ NULL,
105 /* 0x08 */ "Line/Mic 2 Left",
106 /* 0x09 */ "Line/Mic 2 Right",
107 /* 0x0a */ "SPDIF Left",
108 /* 0x0b */ "SPDIF Right",
109 /* 0x0c */ "Aux2 Left",
110 /* 0x0d */ "Aux2 Right",
111 /* 0x0e */ NULL,
112 /* 0x0f */ NULL
113};
114
115static char *creative_outs[32] = {
116 /* 0x00 */ "AC97 Left",
117 /* 0x01 */ "AC97 Right",
118 /* 0x02 */ "Optical IEC958 Left",
119 /* 0x03 */ "Optical IEC958 Right",
120 /* 0x04 */ "Center",
121 /* 0x05 */ "LFE",
122 /* 0x06 */ "Headphone Left",
123 /* 0x07 */ "Headphone Right",
124 /* 0x08 */ "Surround Left",
125 /* 0x09 */ "Surround Right",
126 /* 0x0a */ "PCM Capture Left",
127 /* 0x0b */ "PCM Capture Right",
128 /* 0x0c */ "MIC Capture",
129 /* 0x0d */ "AC97 Surround Left",
130 /* 0x0e */ "AC97 Surround Right",
131 /* 0x0f */ NULL,
132 /* 0x10 */ NULL,
133 /* 0x11 */ "Analog Center",
134 /* 0x12 */ "Analog LFE",
135 /* 0x13 */ NULL,
136 /* 0x14 */ NULL,
137 /* 0x15 */ NULL,
138 /* 0x16 */ NULL,
139 /* 0x17 */ NULL,
140 /* 0x18 */ NULL,
141 /* 0x19 */ NULL,
142 /* 0x1a */ NULL,
143 /* 0x1b */ NULL,
144 /* 0x1c */ NULL,
145 /* 0x1d */ NULL,
146 /* 0x1e */ NULL,
147 /* 0x1f */ NULL,
148};
149
150static char *audigy_outs[32] = {
151 /* 0x00 */ "Digital Front Left",
152 /* 0x01 */ "Digital Front Right",
153 /* 0x02 */ "Digital Center",
154 /* 0x03 */ "Digital LEF",
155 /* 0x04 */ "Headphone Left",
156 /* 0x05 */ "Headphone Right",
157 /* 0x06 */ "Digital Rear Left",
158 /* 0x07 */ "Digital Rear Right",
159 /* 0x08 */ "Front Left",
160 /* 0x09 */ "Front Right",
161 /* 0x0a */ "Center",
162 /* 0x0b */ "LFE",
163 /* 0x0c */ NULL,
164 /* 0x0d */ NULL,
165 /* 0x0e */ "Rear Left",
166 /* 0x0f */ "Rear Right",
167 /* 0x10 */ "AC97 Front Left",
168 /* 0x11 */ "AC97 Front Right",
169 /* 0x12 */ "ADC Caputre Left",
170 /* 0x13 */ "ADC Capture Right",
171 /* 0x14 */ NULL,
172 /* 0x15 */ NULL,
173 /* 0x16 */ NULL,
174 /* 0x17 */ NULL,
175 /* 0x18 */ NULL,
176 /* 0x19 */ NULL,
177 /* 0x1a */ NULL,
178 /* 0x1b */ NULL,
179 /* 0x1c */ NULL,
180 /* 0x1d */ NULL,
181 /* 0x1e */ NULL,
182 /* 0x1f */ NULL,
183};
184
185static const u32 bass_table[41][5] = {
186 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
187 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
188 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
189 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
190 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
191 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
192 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
193 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
194 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
195 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
196 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
197 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
198 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
199 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
200 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
201 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
202 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
203 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
204 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
205 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
206 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
207 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
208 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
209 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
210 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
211 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
212 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
213 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
214 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
215 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
216 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
217 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
218 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
219 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
220 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
221 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
222 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
223 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
224 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
225 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
226 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
227};
228
229static const u32 treble_table[41][5] = {
230 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
231 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
232 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
233 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
234 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
235 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
236 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
237 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
238 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
239 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
240 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
241 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
242 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
243 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
244 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
245 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
246 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
247 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
248 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
249 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
250 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
251 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
252 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
253 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
254 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
255 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
256 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
257 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
258 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
259 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
260 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
261 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
262 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
263 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
264 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
265 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
266 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
267 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
268 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
269 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
270 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
271};
272
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100273/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274static const u32 db_table[101] = {
275 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
276 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
277 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
278 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
279 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
280 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
281 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
282 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
283 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
284 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
285 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
286 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
287 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
288 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
289 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
290 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
291 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
292 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
293 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
294 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
295 0x7fffffff,
296};
297
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100298/* EMU10k1/EMU10k2 DSP control db gain */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100299static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301static const u32 onoff_table[2] = {
302 0x00000000, 0x00000001
303};
304
305/*
306 */
307
308static inline mm_segment_t snd_enter_user(void)
309{
310 mm_segment_t fs = get_fs();
311 set_fs(get_ds());
312 return fs;
313}
314
315static inline void snd_leave_user(mm_segment_t fs)
316{
317 set_fs(fs);
318}
319
320/*
321 * controls
322 */
323
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100324static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100326 struct snd_emu10k1_fx8010_ctl *ctl =
327 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (ctl->min == 0 && ctl->max == 1)
330 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
331 else
332 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
333 uinfo->count = ctl->vcount;
334 uinfo->value.integer.min = ctl->min;
335 uinfo->value.integer.max = ctl->max;
336 return 0;
337}
338
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100339static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100341 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
342 struct snd_emu10k1_fx8010_ctl *ctl =
343 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 unsigned long flags;
345 unsigned int i;
346
347 spin_lock_irqsave(&emu->reg_lock, flags);
348 for (i = 0; i < ctl->vcount; i++)
349 ucontrol->value.integer.value[i] = ctl->value[i];
350 spin_unlock_irqrestore(&emu->reg_lock, flags);
351 return 0;
352}
353
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100354static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100356 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
357 struct snd_emu10k1_fx8010_ctl *ctl =
358 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 unsigned long flags;
360 unsigned int nval, val;
361 unsigned int i, j;
362 int change = 0;
363
364 spin_lock_irqsave(&emu->reg_lock, flags);
365 for (i = 0; i < ctl->vcount; i++) {
366 nval = ucontrol->value.integer.value[i];
367 if (nval < ctl->min)
368 nval = ctl->min;
369 if (nval > ctl->max)
370 nval = ctl->max;
371 if (nval != ctl->value[i])
372 change = 1;
373 val = ctl->value[i] = nval;
374 switch (ctl->translation) {
375 case EMU10K1_GPR_TRANSLATION_NONE:
376 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
377 break;
378 case EMU10K1_GPR_TRANSLATION_TABLE100:
379 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
380 break;
381 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200382 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
383 change = -EIO;
384 goto __error;
385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 for (j = 0; j < 5; j++)
387 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
388 break;
389 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200390 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
391 change = -EIO;
392 goto __error;
393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 for (j = 0; j < 5; j++)
395 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
396 break;
397 case EMU10K1_GPR_TRANSLATION_ONOFF:
398 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
399 break;
400 }
401 }
402 __error:
403 spin_unlock_irqrestore(&emu->reg_lock, flags);
404 return change;
405}
406
407/*
408 * Interrupt handler
409 */
410
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100411static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100413 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 irq = emu->fx8010.irq_handlers;
416 while (irq) {
417 nirq = irq->next; /* irq ptr can be removed from list */
418 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
419 if (irq->handler)
420 irq->handler(emu, irq->private_data);
421 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
422 }
423 irq = nirq;
424 }
425}
426
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100427int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
428 snd_fx8010_irq_handler_t *handler,
429 unsigned char gpr_running,
430 void *private_data,
431 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100433 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 unsigned long flags;
435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
437 if (irq == NULL)
438 return -ENOMEM;
439 irq->handler = handler;
440 irq->gpr_running = gpr_running;
441 irq->private_data = private_data;
442 irq->next = NULL;
443 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
444 if (emu->fx8010.irq_handlers == NULL) {
445 emu->fx8010.irq_handlers = irq;
446 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
447 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
448 } else {
449 irq->next = emu->fx8010.irq_handlers;
450 emu->fx8010.irq_handlers = irq;
451 }
452 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
453 if (r_irq)
454 *r_irq = irq;
455 return 0;
456}
457
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100458int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
459 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100461 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 unsigned long flags;
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
465 if ((tmp = emu->fx8010.irq_handlers) == irq) {
466 emu->fx8010.irq_handlers = tmp->next;
467 if (emu->fx8010.irq_handlers == NULL) {
468 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
469 emu->dsp_interrupt = NULL;
470 }
471 } else {
472 while (tmp && tmp->next != irq)
473 tmp = tmp->next;
474 if (tmp)
475 tmp->next = tmp->next->next;
476 }
477 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
478 kfree(irq);
479 return 0;
480}
481
482/*************************************************************************
483 * EMU10K1 effect manager
484 *************************************************************************/
485
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100486static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
487 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 u32 op, u32 r, u32 a, u32 x, u32 y)
489{
490 u_int32_t *code;
491 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200492 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 set_bit(*ptr, icode->code_valid);
494 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
495 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
496 (*ptr)++;
497}
498
499#define OP(icode, ptr, op, r, a, x, y) \
500 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
501
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100502static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
503 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 u32 op, u32 r, u32 a, u32 x, u32 y)
505{
506 u_int32_t *code;
507 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200508 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 set_bit(*ptr, icode->code_valid);
510 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
511 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
512 (*ptr)++;
513}
514
515#define A_OP(icode, ptr, op, r, a, x, y) \
516 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
517
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100518static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
520 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
521 snd_emu10k1_ptr_write(emu, pc, 0, data);
522}
523
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100524unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
527 return snd_emu10k1_ptr_read(emu, pc, 0);
528}
529
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100530static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
531 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532{
533 int gpr;
534 u32 val;
535
536 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
537 if (!test_bit(gpr, icode->gpr_valid))
538 continue;
539 if (get_user(val, &icode->gpr_map[gpr]))
540 return -EFAULT;
541 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
542 }
543 return 0;
544}
545
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100546static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
547 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548{
549 int gpr;
550 u32 val;
551
552 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
553 set_bit(gpr, icode->gpr_valid);
554 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
555 if (put_user(val, &icode->gpr_map[gpr]))
556 return -EFAULT;
557 }
558 return 0;
559}
560
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100561static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
562 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 int tram;
565 u32 addr, val;
566
567 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
568 if (!test_bit(tram, icode->tram_valid))
569 continue;
570 if (get_user(val, &icode->tram_data_map[tram]) ||
571 get_user(addr, &icode->tram_addr_map[tram]))
572 return -EFAULT;
573 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
574 if (!emu->audigy) {
575 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
576 } else {
577 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
578 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
579 }
580 }
581 return 0;
582}
583
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100584static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
585 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586{
587 int tram;
588 u32 val, addr;
589
590 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
591 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
592 set_bit(tram, icode->tram_valid);
593 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
594 if (!emu->audigy) {
595 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
596 } else {
597 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
598 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
599 }
600 if (put_user(val, &icode->tram_data_map[tram]) ||
601 put_user(addr, &icode->tram_addr_map[tram]))
602 return -EFAULT;
603 }
604 return 0;
605}
606
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100607static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
608 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
610 u32 pc, lo, hi;
611
612 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
613 if (!test_bit(pc / 2, icode->code_valid))
614 continue;
615 if (get_user(lo, &icode->code[pc + 0]) ||
616 get_user(hi, &icode->code[pc + 1]))
617 return -EFAULT;
618 snd_emu10k1_efx_write(emu, pc + 0, lo);
619 snd_emu10k1_efx_write(emu, pc + 1, hi);
620 }
621 return 0;
622}
623
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100624static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
625 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626{
627 u32 pc;
628
629 memset(icode->code_valid, 0, sizeof(icode->code_valid));
630 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
631 set_bit(pc / 2, icode->code_valid);
632 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
633 return -EFAULT;
634 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
635 return -EFAULT;
636 }
637 return 0;
638}
639
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100640static struct snd_emu10k1_fx8010_ctl *
641snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100643 struct snd_emu10k1_fx8010_ctl *ctl;
644 struct snd_kcontrol *kcontrol;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 struct list_head *list;
646
647 list_for_each(list, &emu->fx8010.gpr_ctl) {
648 ctl = emu10k1_gpr_ctl(list);
649 kcontrol = ctl->kcontrol;
650 if (kcontrol->id.iface == id->iface &&
651 !strcmp(kcontrol->id.name, id->name) &&
652 kcontrol->id.index == id->index)
653 return ctl;
654 }
655 return NULL;
656}
657
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100658#define MAX_TLV_SIZE 256
659
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100660static unsigned int *copy_tlv(const unsigned int __user *_tlv)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100661{
662 unsigned int data[2];
663 unsigned int *tlv;
664
665 if (!_tlv)
666 return NULL;
667 if (copy_from_user(data, _tlv, sizeof(data)))
668 return NULL;
669 if (data[1] >= MAX_TLV_SIZE)
670 return NULL;
671 tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
672 if (!tlv)
673 return NULL;
674 memcpy(tlv, data, sizeof(data));
675 if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
676 kfree(tlv);
677 return NULL;
678 }
679 return tlv;
680}
681
682static int copy_gctl(struct snd_emu10k1 *emu,
683 struct snd_emu10k1_fx8010_control_gpr *gctl,
684 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
685 int idx)
686{
687 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
688
689 if (emu->support_tlv)
690 return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
691 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
692 if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
693 return -EFAULT;
694 gctl->tlv = NULL;
695 return 0;
696}
697
698static int copy_gctl_to_user(struct snd_emu10k1 *emu,
699 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
700 struct snd_emu10k1_fx8010_control_gpr *gctl,
701 int idx)
702{
703 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
704
705 if (emu->support_tlv)
706 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
707
708 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
709 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
710}
711
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100712static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
713 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100716 struct snd_ctl_elem_id __user *_id;
717 struct snd_ctl_elem_id id;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100718 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 int err;
720
721 for (i = 0, _id = icode->gpr_del_controls;
722 i < icode->gpr_del_control_count; i++, _id++) {
723 if (copy_from_user(&id, _id, sizeof(id)))
724 return -EFAULT;
725 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
726 return -ENOENT;
727 }
728 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
729 if (! gctl)
730 return -ENOMEM;
731 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100732 for (i = 0; i < icode->gpr_add_control_count; i++) {
733 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 err = -EFAULT;
735 goto __error;
736 }
737 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
738 continue;
739 down_read(&emu->card->controls_rwsem);
740 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
741 up_read(&emu->card->controls_rwsem);
742 err = -EEXIST;
743 goto __error;
744 }
745 up_read(&emu->card->controls_rwsem);
746 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
747 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
748 err = -EINVAL;
749 goto __error;
750 }
751 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100752 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 /* FIXME: we need to check the WRITE access */
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100754 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 err = -EFAULT;
756 goto __error;
757 }
758 }
759 __error:
760 kfree(gctl);
761 return err;
762}
763
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100764static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100766 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100768 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 kctl->private_value = 0;
770 list_del(&ctl->list);
771 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100772 if (kctl->tlv.p)
773 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774}
775
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100776static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
777 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100780 struct snd_emu10k1_fx8010_control_gpr *gctl;
781 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
782 struct snd_kcontrol_new knew;
783 struct snd_kcontrol *kctl;
784 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 int err = 0;
786
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100787 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
789 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
790 if (!val || !gctl || !nctl) {
791 err = -ENOMEM;
792 goto __error;
793 }
794
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100795 for (i = 0; i < icode->gpr_add_control_count; i++) {
796 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 err = -EFAULT;
798 goto __error;
799 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200800 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
801 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
802 err = -EINVAL;
803 goto __error;
804 }
805 if (! gctl->id.name[0]) {
806 err = -EINVAL;
807 goto __error;
808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
810 memset(&knew, 0, sizeof(knew));
811 knew.iface = gctl->id.iface;
812 knew.name = gctl->id.name;
813 knew.index = gctl->id.index;
814 knew.device = gctl->id.device;
815 knew.subdevice = gctl->id.subdevice;
816 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100817 knew.tlv.p = copy_tlv(gctl->tlv);
818 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100819 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
820 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 knew.get = snd_emu10k1_gpr_ctl_get;
822 knew.put = snd_emu10k1_gpr_ctl_put;
823 memset(nctl, 0, sizeof(*nctl));
824 nctl->vcount = gctl->vcount;
825 nctl->count = gctl->count;
826 for (j = 0; j < 32; j++) {
827 nctl->gpr[j] = gctl->gpr[j];
828 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
829 val->value.integer.value[j] = gctl->value[j];
830 }
831 nctl->min = gctl->min;
832 nctl->max = gctl->max;
833 nctl->translation = gctl->translation;
834 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100835 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 if (ctl == NULL) {
837 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100838 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 goto __error;
840 }
841 knew.private_value = (unsigned long)ctl;
842 *ctl = *nctl;
843 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
844 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100845 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 goto __error;
847 }
848 kctl->private_free = snd_emu10k1_ctl_private_free;
849 ctl->kcontrol = kctl;
850 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
851 } else {
852 /* overwrite */
853 nctl->list = ctl->list;
854 nctl->kcontrol = ctl->kcontrol;
855 *ctl = *nctl;
856 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
857 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
858 }
859 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
860 }
861 __error:
862 kfree(nctl);
863 kfree(gctl);
864 kfree(val);
865 return err;
866}
867
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100868static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
869 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870{
871 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100872 struct snd_ctl_elem_id id;
873 struct snd_ctl_elem_id __user *_id;
874 struct snd_emu10k1_fx8010_ctl *ctl;
875 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 for (i = 0, _id = icode->gpr_del_controls;
878 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200879 if (copy_from_user(&id, _id, sizeof(id)))
880 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 down_write(&card->controls_rwsem);
882 ctl = snd_emu10k1_look_for_ctl(emu, &id);
883 if (ctl)
884 snd_ctl_remove(card, ctl->kcontrol);
885 up_write(&card->controls_rwsem);
886 }
887 return 0;
888}
889
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100890static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
891 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
893 unsigned int i = 0, j;
894 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100895 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100896 struct snd_emu10k1_fx8010_ctl *ctl;
897 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 struct list_head *list;
899
900 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
901 if (! gctl)
902 return -ENOMEM;
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 list_for_each(list, &emu->fx8010.gpr_ctl) {
905 ctl = emu10k1_gpr_ctl(list);
906 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100907 if (icode->gpr_list_controls &&
908 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 memset(gctl, 0, sizeof(*gctl));
910 id = &ctl->kcontrol->id;
911 gctl->id.iface = id->iface;
912 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
913 gctl->id.index = id->index;
914 gctl->id.device = id->device;
915 gctl->id.subdevice = id->subdevice;
916 gctl->vcount = ctl->vcount;
917 gctl->count = ctl->count;
918 for (j = 0; j < 32; j++) {
919 gctl->gpr[j] = ctl->gpr[j];
920 gctl->value[j] = ctl->value[j];
921 }
922 gctl->min = ctl->min;
923 gctl->max = ctl->max;
924 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100925 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
926 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 kfree(gctl);
928 return -EFAULT;
929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 i++;
931 }
932 }
933 icode->gpr_list_control_total = total;
934 kfree(gctl);
935 return 0;
936}
937
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100938static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
939 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 int err = 0;
942
Ingo Molnar62932df2006-01-16 16:34:20 +0100943 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
945 goto __error;
946 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
947 /* stop FX processor - this may be dangerous, but it's better to miss
948 some samples than generate wrong ones - [jk] */
949 if (emu->audigy)
950 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
951 else
952 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
953 /* ok, do the main job */
954 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
955 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
956 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
957 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
958 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
959 goto __error;
960 /* start FX processor when the DSP code is updated */
961 if (emu->audigy)
962 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
963 else
964 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
965 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100966 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return err;
968}
969
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100970static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
971 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 int err;
974
Ingo Molnar62932df2006-01-16 16:34:20 +0100975 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
977 /* ok, do the main job */
978 err = snd_emu10k1_gpr_peek(emu, icode);
979 if (err >= 0)
980 err = snd_emu10k1_tram_peek(emu, icode);
981 if (err >= 0)
982 err = snd_emu10k1_code_peek(emu, icode);
983 if (err >= 0)
984 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100985 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 return err;
987}
988
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100989static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
990 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
992 unsigned int i;
993 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100994 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
997 return -EINVAL;
998 if (ipcm->channels > 32)
999 return -EINVAL;
1000 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001001 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 spin_lock_irq(&emu->reg_lock);
1003 if (pcm->opened) {
1004 err = -EBUSY;
1005 goto __error;
1006 }
1007 if (ipcm->channels == 0) { /* remove */
1008 pcm->valid = 0;
1009 } else {
1010 /* FIXME: we need to add universal code to the PCM transfer routine */
1011 if (ipcm->channels != 2) {
1012 err = -EINVAL;
1013 goto __error;
1014 }
1015 pcm->valid = 1;
1016 pcm->opened = 0;
1017 pcm->channels = ipcm->channels;
1018 pcm->tram_start = ipcm->tram_start;
1019 pcm->buffer_size = ipcm->buffer_size;
1020 pcm->gpr_size = ipcm->gpr_size;
1021 pcm->gpr_count = ipcm->gpr_count;
1022 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1023 pcm->gpr_ptr = ipcm->gpr_ptr;
1024 pcm->gpr_trigger = ipcm->gpr_trigger;
1025 pcm->gpr_running = ipcm->gpr_running;
1026 for (i = 0; i < pcm->channels; i++)
1027 pcm->etram[i] = ipcm->etram[i];
1028 }
1029 __error:
1030 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001031 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return err;
1033}
1034
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001035static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1036 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
1038 unsigned int i;
1039 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001040 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
1042 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1043 return -EINVAL;
1044 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001045 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 spin_lock_irq(&emu->reg_lock);
1047 ipcm->channels = pcm->channels;
1048 ipcm->tram_start = pcm->tram_start;
1049 ipcm->buffer_size = pcm->buffer_size;
1050 ipcm->gpr_size = pcm->gpr_size;
1051 ipcm->gpr_ptr = pcm->gpr_ptr;
1052 ipcm->gpr_count = pcm->gpr_count;
1053 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1054 ipcm->gpr_trigger = pcm->gpr_trigger;
1055 ipcm->gpr_running = pcm->gpr_running;
1056 for (i = 0; i < pcm->channels; i++)
1057 ipcm->etram[i] = pcm->etram[i];
1058 ipcm->res1 = ipcm->res2 = 0;
1059 ipcm->pad = 0;
1060 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001061 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return err;
1063}
1064
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001065#define SND_EMU10K1_GPR_CONTROLS 44
1066#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1068#define SND_EMU10K1_CAPTURE_CHANNELS 4
1069
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001070static void __devinit
1071snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1072 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073{
1074 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1075 strcpy(ctl->id.name, name);
1076 ctl->vcount = ctl->count = 1;
1077 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1078 ctl->min = 0;
1079 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001080 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1082}
1083
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001084static void __devinit
1085snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1086 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
1088 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1089 strcpy(ctl->id.name, name);
1090 ctl->vcount = ctl->count = 2;
1091 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1092 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1093 ctl->min = 0;
1094 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001095 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1097}
1098
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001099static void __devinit
1100snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1101 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102{
1103 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1104 strcpy(ctl->id.name, name);
1105 ctl->vcount = ctl->count = 1;
1106 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1107 ctl->min = 0;
1108 ctl->max = 1;
1109 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1110}
1111
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001112static void __devinit
1113snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1114 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
1116 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1117 strcpy(ctl->id.name, name);
1118 ctl->vcount = ctl->count = 2;
1119 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1120 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1121 ctl->min = 0;
1122 ctl->max = 1;
1123 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1124}
1125
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001126static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1127 struct snd_emu10k1_fx8010_code *icode,
1128 u32 *ptr, int tmp, int bit_shifter16,
1129 int reg_in, int reg_out)
1130{
1131 A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
1132 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
1133 A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
1134 A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
1135 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
1136 A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
1137 A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
1138 A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
1139 return 1;
1140}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142/*
1143 * initial DSP configuration for Audigy
1144 */
1145
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001146static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147{
1148 int err, i, z, gpr, nctl;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001149 int bit_shifter16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 const int playback = 10;
1151 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1152 const int stereo_mix = capture + 2;
1153 const int tmp = 0x88;
1154 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001155 struct snd_emu10k1_fx8010_code *icode = NULL;
1156 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 u32 *gpr_map;
1158 mm_segment_t seg;
1159
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001160 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001161 (icode->gpr_map = (u_int32_t __user *)
1162 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1163 GFP_KERNEL)) == NULL ||
1164 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1165 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 err = -ENOMEM;
1167 goto __err;
1168 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001169 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 icode->tram_data_map = icode->gpr_map + 512;
1172 icode->tram_addr_map = icode->tram_data_map + 256;
1173 icode->code = icode->tram_addr_map + 256;
1174
1175 /* clear free GPRs */
1176 for (i = 0; i < 512; i++)
1177 set_bit(i, icode->gpr_valid);
1178
1179 /* clear TRAM data & address lines */
1180 for (i = 0; i < 256; i++)
1181 set_bit(i, icode->tram_valid);
1182
1183 strcpy(icode->name, "Audigy DSP code for ALSA");
1184 ptr = 0;
1185 nctl = 0;
1186 gpr = stereo_mix + 10;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001187 gpr_map[gpr++] = 0x00007fff;
1188 gpr_map[gpr++] = 0x00008000;
1189 gpr_map[gpr++] = 0x0000ffff;
1190 bit_shifter16 = gpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 /* stop FX processor */
1193 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1194
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001195#if 1
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 /* PCM front Playback Volume (independent from stereo mix) */
1197 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1198 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1199 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1200 gpr += 2;
1201
1202 /* PCM Surround Playback (independent from stereo mix) */
1203 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1204 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1205 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1206 gpr += 2;
1207
1208 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001209 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1211 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1212 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1213 gpr += 2;
1214 }
1215
1216 /* PCM Center Playback (independent from stereo mix) */
1217 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1218 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1219 gpr++;
1220
1221 /* PCM LFE Playback (independent from stereo mix) */
1222 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1223 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1224 gpr++;
1225
1226 /*
1227 * Stereo Mix
1228 */
1229 /* Wave (PCM) Playback Volume (will be renamed later) */
1230 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1231 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1232 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1233 gpr += 2;
1234
1235 /* Synth Playback */
1236 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1237 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1238 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1239 gpr += 2;
1240
1241 /* Wave (PCM) Capture */
1242 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1243 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1244 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1245 gpr += 2;
1246
1247 /* Synth Capture */
1248 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1249 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1250 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1251 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 /*
1254 * inputs
1255 */
1256#define A_ADD_VOLUME_IN(var,vol,input) \
1257A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1258
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001259 /* emu1212 DSP 0 and DSP 1 Capture */
1260 if (emu->card_capabilities->emu1010) {
1261 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1262 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1263 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1264 gpr += 2;
1265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 /* AC'97 Playback Volume - used only for mic (renamed later) */
1267 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1268 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1269 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1270 gpr += 2;
1271 /* AC'97 Capture Volume - used only for mic */
1272 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1273 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1274 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1275 gpr += 2;
1276
1277 /* mic capture buffer */
1278 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1279
1280 /* Audigy CD Playback Volume */
1281 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1282 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1283 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001284 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 gpr, 0);
1286 gpr += 2;
1287 /* Audigy CD Capture Volume */
1288 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1289 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1290 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001291 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 gpr, 0);
1293 gpr += 2;
1294
1295 /* Optical SPDIF Playback Volume */
1296 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1297 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001298 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 gpr += 2;
1300 /* Optical SPDIF Capture Volume */
1301 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1302 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001303 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 gpr += 2;
1305
1306 /* Line2 Playback Volume */
1307 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1308 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1309 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001310 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 gpr, 0);
1312 gpr += 2;
1313 /* Line2 Capture Volume */
1314 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1315 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1316 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001317 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 gpr, 0);
1319 gpr += 2;
1320
1321 /* Philips ADC Playback Volume */
1322 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1323 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1324 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1325 gpr += 2;
1326 /* Philips ADC Capture Volume */
1327 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1328 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1329 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1330 gpr += 2;
1331
1332 /* Aux2 Playback Volume */
1333 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1334 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1335 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001336 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 gpr, 0);
1338 gpr += 2;
1339 /* Aux2 Capture Volume */
1340 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1341 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1342 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001343 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 gpr, 0);
1345 gpr += 2;
1346
1347 /* Stereo Mix Front Playback Volume */
1348 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1349 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1350 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1351 gpr += 2;
1352
1353 /* Stereo Mix Surround Playback */
1354 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1355 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1356 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1357 gpr += 2;
1358
1359 /* Stereo Mix Center Playback */
1360 /* Center = sub = Left/2 + Right/2 */
1361 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1362 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1363 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1364 gpr++;
1365
1366 /* Stereo Mix LFE Playback */
1367 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1368 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1369 gpr++;
1370
Lee Revell2b637da2005-03-30 13:51:18 +02001371 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 /* Stereo Mix Side Playback */
1373 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1374 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1375 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1376 gpr += 2;
1377 }
1378
1379 /*
1380 * outputs
1381 */
1382#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1383#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1384 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1385
1386#define _A_SWITCH(icode, ptr, dst, src, sw) \
1387 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1388#define A_SWITCH(icode, ptr, dst, src, sw) \
1389 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1390#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1391 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1392#define A_SWITCH_NEG(icode, ptr, dst, src) \
1393 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1394
1395
1396 /*
1397 * Process tone control
1398 */
1399 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1400 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1401 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 */
1402 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 */
1403 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1404 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 +02001405 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 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 */
1407 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 */
1408 }
1409
1410
1411 ctl = &controls[nctl + 0];
1412 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1413 strcpy(ctl->id.name, "Tone Control - Bass");
1414 ctl->vcount = 2;
1415 ctl->count = 10;
1416 ctl->min = 0;
1417 ctl->max = 40;
1418 ctl->value[0] = ctl->value[1] = 20;
1419 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1420 ctl = &controls[nctl + 1];
1421 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1422 strcpy(ctl->id.name, "Tone Control - Treble");
1423 ctl->vcount = 2;
1424 ctl->count = 10;
1425 ctl->min = 0;
1426 ctl->max = 40;
1427 ctl->value[0] = ctl->value[1] = 20;
1428 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1429
1430#define BASS_GPR 0x8c
1431#define TREBLE_GPR 0x96
1432
1433 for (z = 0; z < 5; z++) {
1434 int j;
1435 for (j = 0; j < 2; j++) {
1436 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1437 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1438 }
1439 }
1440 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1441 int j, k, l, d;
1442 for (j = 0; j < 2; j++) { /* left/right */
1443 k = 0xb0 + (z * 8) + (j * 4);
1444 l = 0xe0 + (z * 8) + (j * 4);
1445 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1446
1447 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1448 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1449 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1450 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1451 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1452 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1453
1454 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1455 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1456 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1457 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1458 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1459 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1460
1461 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1462
1463 if (z == 2) /* center */
1464 break;
1465 }
1466 }
1467 nctl += 2;
1468
1469#undef BASS_GPR
1470#undef TREBLE_GPR
1471
1472 for (z = 0; z < 8; z++) {
1473 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1474 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1475 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1476 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1477 }
1478 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1479 gpr += 2;
1480
1481 /* Master volume (will be renamed later) */
1482 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));
1483 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));
1484 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));
1485 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));
1486 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));
1487 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));
1488 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));
1489 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));
1490 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1491 gpr += 2;
1492
1493 /* analog speakers */
1494 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1495 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1496 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1497 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001498 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1500
1501 /* headphone */
1502 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1503
1504 /* digital outputs */
1505 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001506 if (emu->card_capabilities->emu1010) {
1507 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
1508 snd_printk("EMU outputs on\n");
1509 for (z = 0; z < 8; z++) {
1510 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1511 }
1512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 /* IEC958 Optical Raw Playback Switch */
1515 gpr_map[gpr++] = 0;
1516 gpr_map[gpr++] = 0x1008;
1517 gpr_map[gpr++] = 0xffff0000;
1518 for (z = 0; z < 2; z++) {
1519 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1520 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1521 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1522 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1523 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1524 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1525 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1526 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1527 /* 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 +02001528 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1530 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1531 } else {
1532 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1533 }
1534 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001535 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 -07001536 gpr += 2;
1537
1538 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1539 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1540 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1541
1542 /* ADC buffer */
1543#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1544 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1545#else
1546 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1547 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1548#endif
1549
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001550 if (emu->card_capabilities->emu1010) {
1551 snd_printk("EMU inputs on\n");
1552 /* Capture 8 channels of S32_LE sound */
1553
1554 /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
1555 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1556 /* A_P16VIN(0) is delayed by one sample,
1557 * so all other A_P16VIN channels will need to also be delayed
1558 */
1559 /* Left ADC in. 1 of 2 */
1560 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1561 /* Right ADC in 1 of 2 */
1562 gpr_map[gpr++] = 0x00000000;
1563 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1564 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1565 gpr_map[gpr++] = 0x00000000;
1566 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1567 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
1568 gpr_map[gpr++] = 0x00000000;
1569 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
1570 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1571 /* For 96kHz mode */
1572 /* Left ADC in. 2 of 2 */
1573 gpr_map[gpr++] = 0x00000000;
1574 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1575 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1576 /* Right ADC in 2 of 2 */
1577 gpr_map[gpr++] = 0x00000000;
1578 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1579 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
1580 gpr_map[gpr++] = 0x00000000;
1581 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
1582 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
1583 gpr_map[gpr++] = 0x00000000;
1584 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
1585 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1586
1587#if 0
1588 for (z = 4; z < 8; z++) {
1589 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1590 }
1591 for (z = 0xc; z < 0x10; z++) {
1592 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1593 }
1594#endif
1595 } else {
1596 /* EFX capture - capture the 16 EXTINs */
1597 /* Capture 16 channels of S16_LE sound */
1598 for (z = 0; z < 16; z++) {
1599 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 }
1602
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001603#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 /*
1605 * ok, set up done..
1606 */
1607
1608 if (gpr > tmp) {
1609 snd_BUG();
1610 err = -EIO;
1611 goto __err;
1612 }
1613 /* clear remaining instruction memory */
1614 while (ptr < 0x400)
1615 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1616
1617 seg = snd_enter_user();
1618 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001619 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001620 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001622 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 snd_leave_user(seg);
1624
1625 __err:
1626 kfree(controls);
1627 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001628 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 kfree(icode);
1630 }
1631 return err;
1632}
1633
1634
1635/*
1636 * initial DSP configuration for Emu10k1
1637 */
1638
1639/* when volume = max, then copy only to avoid volume modification */
1640/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001641static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1644 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1645 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1646 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1647}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001648static 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 -07001649{
1650 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1651 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1652 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1653 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1654 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1655}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001656static 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 -07001657{
1658 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1659 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1660 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1661 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1662 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1663}
1664
1665#define VOLUME(icode, ptr, dst, src, vol) \
1666 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1667#define VOLUME_IN(icode, ptr, dst, src, vol) \
1668 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1669#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1670 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1671#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1672 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1673#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1674 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1675#define _SWITCH(icode, ptr, dst, src, sw) \
1676 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1677#define SWITCH(icode, ptr, dst, src, sw) \
1678 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1679#define SWITCH_IN(icode, ptr, dst, src, sw) \
1680 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1681#define _SWITCH_NEG(icode, ptr, dst, src) \
1682 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1683#define SWITCH_NEG(icode, ptr, dst, src) \
1684 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1685
1686
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001687static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688{
1689 int err, i, z, gpr, tmp, playback, capture;
1690 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001691 struct snd_emu10k1_fx8010_code *icode;
1692 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1693 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 u32 *gpr_map;
1695 mm_segment_t seg;
1696
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001697 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001699 if ((icode->gpr_map = (u_int32_t __user *)
1700 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1701 GFP_KERNEL)) == NULL ||
1702 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1703 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1704 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001705 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 err = -ENOMEM;
1707 goto __err;
1708 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001709 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 icode->tram_data_map = icode->gpr_map + 256;
1712 icode->tram_addr_map = icode->tram_data_map + 160;
1713 icode->code = icode->tram_addr_map + 160;
1714
1715 /* clear free GPRs */
1716 for (i = 0; i < 256; i++)
1717 set_bit(i, icode->gpr_valid);
1718
1719 /* clear TRAM data & address lines */
1720 for (i = 0; i < 160; i++)
1721 set_bit(i, icode->tram_valid);
1722
1723 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1724 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001725 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 playback = SND_EMU10K1_INPUTS;
1727 /* we have 6 playback channels and tone control doubles */
1728 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1729 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1730 tmp = 0x88; /* we need 4 temporary GPR */
1731 /* from 0x8c to 0xff is the area for tone control */
1732
1733 /* stop FX processor */
1734 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1735
1736 /*
1737 * Process FX Buses
1738 */
1739 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1740 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1741 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1742 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1743 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1744 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1745 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1746 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1747 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1748 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001749 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1750 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 /* Raw S/PDIF PCM */
1753 ipcm->substream = 0;
1754 ipcm->channels = 2;
1755 ipcm->tram_start = 0;
1756 ipcm->buffer_size = (64 * 1024) / 2;
1757 ipcm->gpr_size = gpr++;
1758 ipcm->gpr_ptr = gpr++;
1759 ipcm->gpr_count = gpr++;
1760 ipcm->gpr_tmpcount = gpr++;
1761 ipcm->gpr_trigger = gpr++;
1762 ipcm->gpr_running = gpr++;
1763 ipcm->etram[0] = 0;
1764 ipcm->etram[1] = 1;
1765
1766 gpr_map[gpr + 0] = 0xfffff000;
1767 gpr_map[gpr + 1] = 0xffff0000;
1768 gpr_map[gpr + 2] = 0x70000000;
1769 gpr_map[gpr + 3] = 0x00000007;
1770 gpr_map[gpr + 4] = 0x001f << 11;
1771 gpr_map[gpr + 5] = 0x001c << 11;
1772 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1773 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1774 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1775 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1776 gpr_map[gpr + 10] = 1<<11;
1777 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1778 gpr_map[gpr + 12] = 0;
1779
1780 /* if the trigger flag is not set, skip */
1781 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1782 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1783 /* if the running flag is set, we're running */
1784 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1785 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1786 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1787 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1788 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1789 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1790 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1791
1792 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1793 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1794 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1795 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1796
1797 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1798 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1799 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1800 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1801 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1802
1803 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1804 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1805 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1806 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1807 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1808
1809 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1810 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1811 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1812 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1813 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1814
1815 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1816 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1817 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1818 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1819 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1820
1821 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1822 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1823
1824 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1825 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1826
1827 /* 24: */
1828 gpr += 13;
1829
1830 /* Wave Playback Volume */
1831 for (z = 0; z < 2; z++)
1832 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1833 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1834 gpr += 2;
1835
1836 /* Wave Surround Playback Volume */
1837 for (z = 0; z < 2; z++)
1838 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1839 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1840 gpr += 2;
1841
1842 /* Wave Center/LFE Playback Volume */
1843 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1844 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1845 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1846 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1847 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1848 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1849
1850 /* Wave Capture Volume + Switch */
1851 for (z = 0; z < 2; z++) {
1852 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1853 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1854 }
1855 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1856 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1857 gpr += 4;
1858
1859 /* Synth Playback Volume */
1860 for (z = 0; z < 2; z++)
1861 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1862 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1863 gpr += 2;
1864
1865 /* Synth Capture Volume + Switch */
1866 for (z = 0; z < 2; z++) {
1867 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1868 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1869 }
1870 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1871 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1872 gpr += 4;
1873
1874 /* Surround Digital Playback Volume (renamed later without Digital) */
1875 for (z = 0; z < 2; z++)
1876 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1877 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1878 gpr += 2;
1879
1880 /* Surround Capture Volume + Switch */
1881 for (z = 0; z < 2; z++) {
1882 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1883 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1884 }
1885 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1886 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1887 gpr += 4;
1888
1889 /* Center Playback Volume (renamed later without Digital) */
1890 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1891 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1892
1893 /* LFE Playback Volume + Switch (renamed later without Digital) */
1894 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1895 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1896
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001897 /* Front Playback Volume */
1898 for (z = 0; z < 2; z++)
1899 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1900 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1901 gpr += 2;
1902
1903 /* Front Capture Volume + Switch */
1904 for (z = 0; z < 2; z++) {
1905 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1906 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1907 }
1908 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
1909 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
1910 gpr += 3;
1911
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 /*
1913 * Process inputs
1914 */
1915
1916 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
1917 /* AC'97 Playback Volume */
1918 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
1919 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
1920 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
1921 /* AC'97 Capture Volume */
1922 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
1923 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
1924 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
1925 }
1926
1927 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
1928 /* IEC958 TTL Playback Volume */
1929 for (z = 0; z < 2; z++)
1930 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001931 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 gpr += 2;
1933
1934 /* IEC958 TTL Capture Volume + Switch */
1935 for (z = 0; z < 2; z++) {
1936 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
1937 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1938 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001939 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
1940 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 -07001941 gpr += 4;
1942 }
1943
1944 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
1945 /* Zoom Video Playback Volume */
1946 for (z = 0; z < 2; z++)
1947 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
1948 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
1949 gpr += 2;
1950
1951 /* Zoom Video Capture Volume + Switch */
1952 for (z = 0; z < 2; z++) {
1953 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
1954 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1955 }
1956 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
1957 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
1958 gpr += 4;
1959 }
1960
1961 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
1962 /* IEC958 Optical Playback Volume */
1963 for (z = 0; z < 2; z++)
1964 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001965 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 gpr += 2;
1967
1968 /* IEC958 Optical Capture Volume */
1969 for (z = 0; z < 2; z++) {
1970 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
1971 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1972 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001973 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
1974 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 -07001975 gpr += 4;
1976 }
1977
1978 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
1979 /* Line LiveDrive Playback Volume */
1980 for (z = 0; z < 2; z++)
1981 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
1982 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
1983 gpr += 2;
1984
1985 /* Line LiveDrive Capture Volume + Switch */
1986 for (z = 0; z < 2; z++) {
1987 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
1988 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1989 }
1990 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
1991 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
1992 gpr += 4;
1993 }
1994
1995 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
1996 /* IEC958 Coax Playback Volume */
1997 for (z = 0; z < 2; z++)
1998 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001999 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 gpr += 2;
2001
2002 /* IEC958 Coax Capture Volume + Switch */
2003 for (z = 0; z < 2; z++) {
2004 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2005 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2006 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002007 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2008 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 -07002009 gpr += 4;
2010 }
2011
2012 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2013 /* Line LiveDrive Playback Volume */
2014 for (z = 0; z < 2; z++)
2015 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2016 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2017 controls[i-1].id.index = 1;
2018 gpr += 2;
2019
2020 /* Line LiveDrive Capture Volume */
2021 for (z = 0; z < 2; z++) {
2022 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2023 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2024 }
2025 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2026 controls[i-1].id.index = 1;
2027 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2028 controls[i-1].id.index = 1;
2029 gpr += 4;
2030 }
2031
2032 /*
2033 * Process tone control
2034 */
2035 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2036 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2037 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2038 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2039 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2040 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2041
2042 ctl = &controls[i + 0];
2043 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2044 strcpy(ctl->id.name, "Tone Control - Bass");
2045 ctl->vcount = 2;
2046 ctl->count = 10;
2047 ctl->min = 0;
2048 ctl->max = 40;
2049 ctl->value[0] = ctl->value[1] = 20;
2050 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2051 ctl = &controls[i + 1];
2052 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2053 strcpy(ctl->id.name, "Tone Control - Treble");
2054 ctl->vcount = 2;
2055 ctl->count = 10;
2056 ctl->min = 0;
2057 ctl->max = 40;
2058 ctl->value[0] = ctl->value[1] = 20;
2059 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2060
2061#define BASS_GPR 0x8c
2062#define TREBLE_GPR 0x96
2063
2064 for (z = 0; z < 5; z++) {
2065 int j;
2066 for (j = 0; j < 2; j++) {
2067 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2068 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2069 }
2070 }
2071 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2072 int j, k, l, d;
2073 for (j = 0; j < 2; j++) { /* left/right */
2074 k = 0xa0 + (z * 8) + (j * 4);
2075 l = 0xd0 + (z * 8) + (j * 4);
2076 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2077
2078 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2079 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2080 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2081 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2082 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2083 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2084
2085 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2086 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2087 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2088 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2089 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2090 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2091
2092 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2093
2094 if (z == 2) /* center */
2095 break;
2096 }
2097 }
2098 i += 2;
2099
2100#undef BASS_GPR
2101#undef TREBLE_GPR
2102
2103 for (z = 0; z < 6; z++) {
2104 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2105 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2106 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2107 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2108 }
2109 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2110 gpr += 2;
2111
2112 /*
2113 * Process outputs
2114 */
2115 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2116 /* AC'97 Playback Volume */
2117
2118 for (z = 0; z < 2; z++)
2119 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2120 }
2121
2122 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2123 /* IEC958 Optical Raw Playback Switch */
2124
2125 for (z = 0; z < 2; z++) {
2126 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2127 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2128 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2129 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2130#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2131 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2132#endif
2133 }
2134
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002135 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 -07002136 gpr += 2;
2137 }
2138
2139 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2140 /* Headphone Playback Volume */
2141
2142 for (z = 0; z < 2; z++) {
2143 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2144 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2145 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2146 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2147 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2148 }
2149
2150 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2151 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2152 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2153 controls[i-1].id.index = 1;
2154 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2155 controls[i-1].id.index = 1;
2156
2157 gpr += 4;
2158 }
2159
2160 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2161 for (z = 0; z < 2; z++)
2162 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2163
2164 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2165 for (z = 0; z < 2; z++)
2166 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2167
2168 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2169#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2170 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2171 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2172#else
2173 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2174 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2175#endif
2176 }
2177
2178 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2179#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2180 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2181 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2182#else
2183 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2184 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2185#endif
2186 }
2187
2188#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2189 for (z = 0; z < 2; z++)
2190 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2191#endif
2192
2193 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2194 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2195
2196 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002197 if (emu->card_capabilities->sblive51) {
2198 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2199 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2200 *
2201 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2202 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2203 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2204 * channel. Multitrack recorders will still see the center/lfe output signal
2205 * on the second and third channels.
2206 */
2207 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2208 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2209 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2210 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2211 for (z = 4; z < 14; z++)
2212 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2213 } else {
2214 for (z = 0; z < 16; z++)
2215 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 }
Lee Revell2b637da2005-03-30 13:51:18 +02002217
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219 if (gpr > tmp) {
2220 snd_BUG();
2221 err = -EIO;
2222 goto __err;
2223 }
2224 if (i > SND_EMU10K1_GPR_CONTROLS) {
2225 snd_BUG();
2226 err = -EIO;
2227 goto __err;
2228 }
2229
2230 /* clear remaining instruction memory */
2231 while (ptr < 0x200)
2232 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2233
2234 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2235 goto __err;
2236 seg = snd_enter_user();
2237 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002238 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002239 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002241 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 snd_leave_user(seg);
2243 if (err >= 0)
2244 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2245 __err:
2246 kfree(ipcm);
2247 kfree(controls);
2248 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002249 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 kfree(icode);
2251 }
2252 return err;
2253}
2254
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002255int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256{
Takashi Iwai09668b42005-11-17 16:14:10 +01002257 spin_lock_init(&emu->fx8010.irq_lock);
2258 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if (emu->audigy)
2260 return _snd_emu10k1_audigy_init_efx(emu);
2261 else
2262 return _snd_emu10k1_init_efx(emu);
2263}
2264
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002265void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266{
2267 /* stop processor */
2268 if (emu->audigy)
2269 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2270 else
2271 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2272}
2273
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002274#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002275int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002277 if (output < 0 || output >= 6)
2278 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2280 return 0;
2281}
2282
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002283int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002285 if (output < 0 || output >= 6)
2286 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2288 return 0;
2289}
2290#endif
2291
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002292int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293{
2294 u8 size_reg = 0;
2295
2296 /* size is in samples */
2297 if (size != 0) {
2298 size = (size - 1) >> 13;
2299
2300 while (size) {
2301 size >>= 1;
2302 size_reg++;
2303 }
2304 size = 0x2000 << size_reg;
2305 }
2306 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2307 return 0;
2308 spin_lock_irq(&emu->emu_lock);
2309 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2310 spin_unlock_irq(&emu->emu_lock);
2311 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2312 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2313 if (emu->fx8010.etram_pages.area != NULL) {
2314 snd_dma_free_pages(&emu->fx8010.etram_pages);
2315 emu->fx8010.etram_pages.area = NULL;
2316 emu->fx8010.etram_pages.bytes = 0;
2317 }
2318
2319 if (size > 0) {
2320 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2321 size * 2, &emu->fx8010.etram_pages) < 0)
2322 return -ENOMEM;
2323 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2324 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2325 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2326 spin_lock_irq(&emu->emu_lock);
2327 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002328 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 }
2330
2331 return 0;
2332}
2333
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002334static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335{
2336 return 0;
2337}
2338
2339static void copy_string(char *dst, char *src, char *null, int idx)
2340{
2341 if (src == NULL)
2342 sprintf(dst, "%s %02X", null, idx);
2343 else
2344 strcpy(dst, src);
2345}
2346
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002347static int snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2348 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349{
2350 char **fxbus, **extin, **extout;
2351 unsigned short fxbus_mask, extin_mask, extout_mask;
2352 int res;
2353
2354 memset(info, 0, sizeof(info));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 info->internal_tram_size = emu->fx8010.itram_size;
2356 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2357 fxbus = fxbuses;
2358 extin = emu->audigy ? audigy_ins : creative_ins;
2359 extout = emu->audigy ? audigy_outs : creative_outs;
2360 fxbus_mask = emu->fx8010.fxbus_mask;
2361 extin_mask = emu->fx8010.extin_mask;
2362 extout_mask = emu->fx8010.extout_mask;
2363 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2364 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2365 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2366 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2367 }
2368 for (res = 16; res < 32; res++, extout++)
2369 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2370 info->gpr_controls = emu->fx8010.gpr_count;
2371 return 0;
2372}
2373
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002374static 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 -07002375{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002376 struct snd_emu10k1 *emu = hw->private_data;
2377 struct snd_emu10k1_fx8010_info *info;
2378 struct snd_emu10k1_fx8010_code *icode;
2379 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 unsigned int addr;
2381 void __user *argp = (void __user *)arg;
2382 int res;
2383
2384 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002385 case SNDRV_EMU10K1_IOCTL_PVERSION:
2386 emu->support_tlv = 1;
2387 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002389 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 if (!info)
2391 return -ENOMEM;
2392 if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) {
2393 kfree(info);
2394 return res;
2395 }
2396 if (copy_to_user(argp, info, sizeof(*info))) {
2397 kfree(info);
2398 return -EFAULT;
2399 }
2400 kfree(info);
2401 return 0;
2402 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2403 if (!capable(CAP_SYS_ADMIN))
2404 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002405 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 if (icode == NULL)
2407 return -ENOMEM;
2408 if (copy_from_user(icode, argp, sizeof(*icode))) {
2409 kfree(icode);
2410 return -EFAULT;
2411 }
2412 res = snd_emu10k1_icode_poke(emu, icode);
2413 kfree(icode);
2414 return res;
2415 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002416 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 if (icode == NULL)
2418 return -ENOMEM;
2419 if (copy_from_user(icode, argp, sizeof(*icode))) {
2420 kfree(icode);
2421 return -EFAULT;
2422 }
2423 res = snd_emu10k1_icode_peek(emu, icode);
2424 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2425 kfree(icode);
2426 return -EFAULT;
2427 }
2428 kfree(icode);
2429 return res;
2430 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002431 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 if (ipcm == NULL)
2433 return -ENOMEM;
2434 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2435 kfree(ipcm);
2436 return -EFAULT;
2437 }
2438 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2439 kfree(ipcm);
2440 return res;
2441 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002442 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 if (ipcm == NULL)
2444 return -ENOMEM;
2445 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2446 kfree(ipcm);
2447 return -EFAULT;
2448 }
2449 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2450 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2451 kfree(ipcm);
2452 return -EFAULT;
2453 }
2454 kfree(ipcm);
2455 return res;
2456 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2457 if (!capable(CAP_SYS_ADMIN))
2458 return -EPERM;
2459 if (get_user(addr, (unsigned int __user *)argp))
2460 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002461 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002463 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 return res;
2465 case SNDRV_EMU10K1_IOCTL_STOP:
2466 if (!capable(CAP_SYS_ADMIN))
2467 return -EPERM;
2468 if (emu->audigy)
2469 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2470 else
2471 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2472 return 0;
2473 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2474 if (!capable(CAP_SYS_ADMIN))
2475 return -EPERM;
2476 if (emu->audigy)
2477 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2478 else
2479 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2480 return 0;
2481 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2482 if (!capable(CAP_SYS_ADMIN))
2483 return -EPERM;
2484 if (emu->audigy)
2485 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2486 else
2487 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2488 udelay(10);
2489 if (emu->audigy)
2490 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2491 else
2492 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2493 return 0;
2494 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2495 if (!capable(CAP_SYS_ADMIN))
2496 return -EPERM;
2497 if (get_user(addr, (unsigned int __user *)argp))
2498 return -EFAULT;
2499 if (addr > 0x1ff)
2500 return -EINVAL;
2501 if (emu->audigy)
2502 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2503 else
2504 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2505 udelay(10);
2506 if (emu->audigy)
2507 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2508 else
2509 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2510 return 0;
2511 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2512 if (emu->audigy)
2513 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2514 else
2515 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2516 if (put_user(addr, (unsigned int __user *)argp))
2517 return -EFAULT;
2518 return 0;
2519 }
2520 return -ENOTTY;
2521}
2522
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002523static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524{
2525 return 0;
2526}
2527
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002528int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002530 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 int err;
2532
2533 if (rhwdep)
2534 *rhwdep = NULL;
2535 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2536 return err;
2537 strcpy(hw->name, "EMU10K1 (FX8010)");
2538 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2539 hw->ops.open = snd_emu10k1_fx8010_open;
2540 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2541 hw->ops.release = snd_emu10k1_fx8010_release;
2542 hw->private_data = emu;
2543 if (rhwdep)
2544 *rhwdep = hw;
2545 return 0;
2546}
Takashi Iwai09668b42005-11-17 16:14:10 +01002547
2548#ifdef CONFIG_PM
2549int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2550{
2551 int len;
2552
2553 len = emu->audigy ? 0x200 : 0x100;
2554 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2555 if (! emu->saved_gpr)
2556 return -ENOMEM;
2557 len = emu->audigy ? 0x100 : 0xa0;
2558 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2559 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2560 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2561 return -ENOMEM;
2562 len = emu->audigy ? 2 * 1024 : 2 * 512;
2563 emu->saved_icode = vmalloc(len * 4);
2564 if (! emu->saved_icode)
2565 return -ENOMEM;
2566 return 0;
2567}
2568
2569void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2570{
2571 kfree(emu->saved_gpr);
2572 kfree(emu->tram_val_saved);
2573 kfree(emu->tram_addr_saved);
2574 vfree(emu->saved_icode);
2575}
2576
2577/*
2578 * save/restore GPR, TRAM and codes
2579 */
2580void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2581{
2582 int i, len;
2583
2584 len = emu->audigy ? 0x200 : 0x100;
2585 for (i = 0; i < len; i++)
2586 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2587
2588 len = emu->audigy ? 0x100 : 0xa0;
2589 for (i = 0; i < len; i++) {
2590 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2591 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2592 if (emu->audigy) {
2593 emu->tram_addr_saved[i] >>= 12;
2594 emu->tram_addr_saved[i] |=
2595 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2596 }
2597 }
2598
2599 len = emu->audigy ? 2 * 1024 : 2 * 512;
2600 for (i = 0; i < len; i++)
2601 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2602}
2603
2604void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2605{
2606 int i, len;
2607
2608 /* set up TRAM */
2609 if (emu->fx8010.etram_pages.bytes > 0) {
2610 unsigned size, size_reg = 0;
2611 size = emu->fx8010.etram_pages.bytes / 2;
2612 size = (size - 1) >> 13;
2613 while (size) {
2614 size >>= 1;
2615 size_reg++;
2616 }
2617 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2618 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2619 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2620 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2621 }
2622
2623 if (emu->audigy)
2624 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2625 else
2626 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2627
2628 len = emu->audigy ? 0x200 : 0x100;
2629 for (i = 0; i < len; i++)
2630 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2631
2632 len = emu->audigy ? 0x100 : 0xa0;
2633 for (i = 0; i < len; i++) {
2634 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2635 emu->tram_val_saved[i]);
2636 if (! emu->audigy)
2637 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2638 emu->tram_addr_saved[i]);
2639 else {
2640 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2641 emu->tram_addr_saved[i] << 12);
2642 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2643 emu->tram_addr_saved[i] >> 20);
2644 }
2645 }
2646
2647 len = emu->audigy ? 2 * 1024 : 2 * 512;
2648 for (i = 0; i < len; i++)
2649 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2650
2651 /* start FX processor when the DSP code is updated */
2652 if (emu->audigy)
2653 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2654 else
2655 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2656}
2657#endif