blob: 71dc4c8865b88323edbe13a811c5171061d26e51 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02002 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/pci.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/delay.h>
34#include <linux/slab.h>
Andreas Schwabbd01e7b2005-12-05 15:12:20 +010035#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/init.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010037#include <linux/mutex.h>
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <sound/core.h>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010040#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <sound/emu10k1.h>
42
43#if 0 /* for testing purposes - digital out -> capture */
44#define EMU10K1_CAPTURE_DIGITAL_OUT
45#endif
46#if 0 /* for testing purposes - set S/PDIF to AC3 output */
47#define EMU10K1_SET_AC3_IEC958
48#endif
49#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
50#define EMU10K1_CENTER_LFE_FROM_FRONT
51#endif
52
53/*
54 * Tables
55 */
56
57static char *fxbuses[16] = {
58 /* 0x00 */ "PCM Left",
59 /* 0x01 */ "PCM Right",
60 /* 0x02 */ "PCM Surround Left",
61 /* 0x03 */ "PCM Surround Right",
62 /* 0x04 */ "MIDI Left",
63 /* 0x05 */ "MIDI Right",
64 /* 0x06 */ "Center",
65 /* 0x07 */ "LFE",
66 /* 0x08 */ NULL,
67 /* 0x09 */ NULL,
68 /* 0x0a */ NULL,
69 /* 0x0b */ NULL,
70 /* 0x0c */ "MIDI Reverb",
71 /* 0x0d */ "MIDI Chorus",
72 /* 0x0e */ NULL,
73 /* 0x0f */ NULL
74};
75
76static char *creative_ins[16] = {
77 /* 0x00 */ "AC97 Left",
78 /* 0x01 */ "AC97 Right",
79 /* 0x02 */ "TTL IEC958 Left",
80 /* 0x03 */ "TTL IEC958 Right",
81 /* 0x04 */ "Zoom Video Left",
82 /* 0x05 */ "Zoom Video Right",
83 /* 0x06 */ "Optical IEC958 Left",
84 /* 0x07 */ "Optical IEC958 Right",
85 /* 0x08 */ "Line/Mic 1 Left",
86 /* 0x09 */ "Line/Mic 1 Right",
87 /* 0x0a */ "Coaxial IEC958 Left",
88 /* 0x0b */ "Coaxial IEC958 Right",
89 /* 0x0c */ "Line/Mic 2 Left",
90 /* 0x0d */ "Line/Mic 2 Right",
91 /* 0x0e */ NULL,
92 /* 0x0f */ NULL
93};
94
95static char *audigy_ins[16] = {
96 /* 0x00 */ "AC97 Left",
97 /* 0x01 */ "AC97 Right",
98 /* 0x02 */ "Audigy CD Left",
99 /* 0x03 */ "Audigy CD Right",
100 /* 0x04 */ "Optical IEC958 Left",
101 /* 0x05 */ "Optical IEC958 Right",
102 /* 0x06 */ NULL,
103 /* 0x07 */ NULL,
104 /* 0x08 */ "Line/Mic 2 Left",
105 /* 0x09 */ "Line/Mic 2 Right",
106 /* 0x0a */ "SPDIF Left",
107 /* 0x0b */ "SPDIF Right",
108 /* 0x0c */ "Aux2 Left",
109 /* 0x0d */ "Aux2 Right",
110 /* 0x0e */ NULL,
111 /* 0x0f */ NULL
112};
113
114static char *creative_outs[32] = {
115 /* 0x00 */ "AC97 Left",
116 /* 0x01 */ "AC97 Right",
117 /* 0x02 */ "Optical IEC958 Left",
118 /* 0x03 */ "Optical IEC958 Right",
119 /* 0x04 */ "Center",
120 /* 0x05 */ "LFE",
121 /* 0x06 */ "Headphone Left",
122 /* 0x07 */ "Headphone Right",
123 /* 0x08 */ "Surround Left",
124 /* 0x09 */ "Surround Right",
125 /* 0x0a */ "PCM Capture Left",
126 /* 0x0b */ "PCM Capture Right",
127 /* 0x0c */ "MIC Capture",
128 /* 0x0d */ "AC97 Surround Left",
129 /* 0x0e */ "AC97 Surround Right",
130 /* 0x0f */ NULL,
131 /* 0x10 */ NULL,
132 /* 0x11 */ "Analog Center",
133 /* 0x12 */ "Analog LFE",
134 /* 0x13 */ NULL,
135 /* 0x14 */ NULL,
136 /* 0x15 */ NULL,
137 /* 0x16 */ NULL,
138 /* 0x17 */ NULL,
139 /* 0x18 */ NULL,
140 /* 0x19 */ NULL,
141 /* 0x1a */ NULL,
142 /* 0x1b */ NULL,
143 /* 0x1c */ NULL,
144 /* 0x1d */ NULL,
145 /* 0x1e */ NULL,
146 /* 0x1f */ NULL,
147};
148
149static char *audigy_outs[32] = {
150 /* 0x00 */ "Digital Front Left",
151 /* 0x01 */ "Digital Front Right",
152 /* 0x02 */ "Digital Center",
153 /* 0x03 */ "Digital LEF",
154 /* 0x04 */ "Headphone Left",
155 /* 0x05 */ "Headphone Right",
156 /* 0x06 */ "Digital Rear Left",
157 /* 0x07 */ "Digital Rear Right",
158 /* 0x08 */ "Front Left",
159 /* 0x09 */ "Front Right",
160 /* 0x0a */ "Center",
161 /* 0x0b */ "LFE",
162 /* 0x0c */ NULL,
163 /* 0x0d */ NULL,
164 /* 0x0e */ "Rear Left",
165 /* 0x0f */ "Rear Right",
166 /* 0x10 */ "AC97 Front Left",
167 /* 0x11 */ "AC97 Front Right",
168 /* 0x12 */ "ADC Caputre Left",
169 /* 0x13 */ "ADC Capture Right",
170 /* 0x14 */ NULL,
171 /* 0x15 */ NULL,
172 /* 0x16 */ NULL,
173 /* 0x17 */ NULL,
174 /* 0x18 */ NULL,
175 /* 0x19 */ NULL,
176 /* 0x1a */ NULL,
177 /* 0x1b */ NULL,
178 /* 0x1c */ NULL,
179 /* 0x1d */ NULL,
180 /* 0x1e */ NULL,
181 /* 0x1f */ NULL,
182};
183
184static const u32 bass_table[41][5] = {
185 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
186 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
187 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
188 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
189 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
190 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
191 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
192 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
193 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
194 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
195 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
196 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
197 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
198 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
199 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
200 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
201 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
202 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
203 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
204 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
205 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
206 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
207 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
208 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
209 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
210 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
211 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
212 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
213 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
214 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
215 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
216 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
217 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
218 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
219 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
220 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
221 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
222 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
223 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
224 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
225 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
226};
227
228static const u32 treble_table[41][5] = {
229 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
230 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
231 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
232 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
233 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
234 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
235 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
236 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
237 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
238 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
239 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
240 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
241 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
242 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
243 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
244 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
245 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
246 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
247 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
248 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
249 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
250 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
251 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
252 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
253 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
254 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
255 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
256 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
257 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
258 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
259 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
260 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
261 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
262 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
263 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
264 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
265 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
266 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
267 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
268 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
269 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
270};
271
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100272/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273static const u32 db_table[101] = {
274 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
275 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
276 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
277 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
278 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
279 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
280 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
281 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
282 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
283 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
284 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
285 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
286 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
287 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
288 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
289 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
290 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
291 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
292 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
293 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
294 0x7fffffff,
295};
296
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100297/* EMU10k1/EMU10k2 DSP control db gain */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100298static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300static const u32 onoff_table[2] = {
301 0x00000000, 0x00000001
302};
303
304/*
305 */
306
307static inline mm_segment_t snd_enter_user(void)
308{
309 mm_segment_t fs = get_fs();
310 set_fs(get_ds());
311 return fs;
312}
313
314static inline void snd_leave_user(mm_segment_t fs)
315{
316 set_fs(fs);
317}
318
319/*
320 * controls
321 */
322
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100323static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100325 struct snd_emu10k1_fx8010_ctl *ctl =
326 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (ctl->min == 0 && ctl->max == 1)
329 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
330 else
331 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
332 uinfo->count = ctl->vcount;
333 uinfo->value.integer.min = ctl->min;
334 uinfo->value.integer.max = ctl->max;
335 return 0;
336}
337
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100338static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100340 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
341 struct snd_emu10k1_fx8010_ctl *ctl =
342 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 unsigned long flags;
344 unsigned int i;
345
346 spin_lock_irqsave(&emu->reg_lock, flags);
347 for (i = 0; i < ctl->vcount; i++)
348 ucontrol->value.integer.value[i] = ctl->value[i];
349 spin_unlock_irqrestore(&emu->reg_lock, flags);
350 return 0;
351}
352
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100353static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100355 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
356 struct snd_emu10k1_fx8010_ctl *ctl =
357 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 unsigned long flags;
359 unsigned int nval, val;
360 unsigned int i, j;
361 int change = 0;
362
363 spin_lock_irqsave(&emu->reg_lock, flags);
364 for (i = 0; i < ctl->vcount; i++) {
365 nval = ucontrol->value.integer.value[i];
366 if (nval < ctl->min)
367 nval = ctl->min;
368 if (nval > ctl->max)
369 nval = ctl->max;
370 if (nval != ctl->value[i])
371 change = 1;
372 val = ctl->value[i] = nval;
373 switch (ctl->translation) {
374 case EMU10K1_GPR_TRANSLATION_NONE:
375 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
376 break;
377 case EMU10K1_GPR_TRANSLATION_TABLE100:
378 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
379 break;
380 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200381 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
382 change = -EIO;
383 goto __error;
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 for (j = 0; j < 5; j++)
386 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
387 break;
388 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200389 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
390 change = -EIO;
391 goto __error;
392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 for (j = 0; j < 5; j++)
394 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
395 break;
396 case EMU10K1_GPR_TRANSLATION_ONOFF:
397 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
398 break;
399 }
400 }
401 __error:
402 spin_unlock_irqrestore(&emu->reg_lock, flags);
403 return change;
404}
405
406/*
407 * Interrupt handler
408 */
409
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100410static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100412 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 irq = emu->fx8010.irq_handlers;
415 while (irq) {
416 nirq = irq->next; /* irq ptr can be removed from list */
417 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
418 if (irq->handler)
419 irq->handler(emu, irq->private_data);
420 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
421 }
422 irq = nirq;
423 }
424}
425
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100426int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
427 snd_fx8010_irq_handler_t *handler,
428 unsigned char gpr_running,
429 void *private_data,
430 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100432 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 unsigned long flags;
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
436 if (irq == NULL)
437 return -ENOMEM;
438 irq->handler = handler;
439 irq->gpr_running = gpr_running;
440 irq->private_data = private_data;
441 irq->next = NULL;
442 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
443 if (emu->fx8010.irq_handlers == NULL) {
444 emu->fx8010.irq_handlers = irq;
445 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
446 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
447 } else {
448 irq->next = emu->fx8010.irq_handlers;
449 emu->fx8010.irq_handlers = irq;
450 }
451 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
452 if (r_irq)
453 *r_irq = irq;
454 return 0;
455}
456
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100457int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
458 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100460 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 unsigned long flags;
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
464 if ((tmp = emu->fx8010.irq_handlers) == irq) {
465 emu->fx8010.irq_handlers = tmp->next;
466 if (emu->fx8010.irq_handlers == NULL) {
467 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
468 emu->dsp_interrupt = NULL;
469 }
470 } else {
471 while (tmp && tmp->next != irq)
472 tmp = tmp->next;
473 if (tmp)
474 tmp->next = tmp->next->next;
475 }
476 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
477 kfree(irq);
478 return 0;
479}
480
481/*************************************************************************
482 * EMU10K1 effect manager
483 *************************************************************************/
484
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100485static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
486 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 u32 op, u32 r, u32 a, u32 x, u32 y)
488{
489 u_int32_t *code;
490 snd_assert(*ptr < 512, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200491 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 set_bit(*ptr, icode->code_valid);
493 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
494 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
495 (*ptr)++;
496}
497
498#define OP(icode, ptr, op, r, a, x, y) \
499 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
500
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100501static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
502 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 u32 op, u32 r, u32 a, u32 x, u32 y)
504{
505 u_int32_t *code;
506 snd_assert(*ptr < 1024, return);
Clemens Ladisch4d233592005-09-05 10:35:20 +0200507 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 set_bit(*ptr, icode->code_valid);
509 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
510 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
511 (*ptr)++;
512}
513
514#define A_OP(icode, ptr, op, r, a, x, y) \
515 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
516
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100517static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
520 snd_emu10k1_ptr_write(emu, pc, 0, data);
521}
522
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100523unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
526 return snd_emu10k1_ptr_read(emu, pc, 0);
527}
528
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100529static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
530 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531{
532 int gpr;
533 u32 val;
534
535 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
536 if (!test_bit(gpr, icode->gpr_valid))
537 continue;
538 if (get_user(val, &icode->gpr_map[gpr]))
539 return -EFAULT;
540 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
541 }
542 return 0;
543}
544
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100545static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
546 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547{
548 int gpr;
549 u32 val;
550
551 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
552 set_bit(gpr, icode->gpr_valid);
553 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
554 if (put_user(val, &icode->gpr_map[gpr]))
555 return -EFAULT;
556 }
557 return 0;
558}
559
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100560static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
561 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562{
563 int tram;
564 u32 addr, val;
565
566 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
567 if (!test_bit(tram, icode->tram_valid))
568 continue;
569 if (get_user(val, &icode->tram_data_map[tram]) ||
570 get_user(addr, &icode->tram_addr_map[tram]))
571 return -EFAULT;
572 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
573 if (!emu->audigy) {
574 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
575 } else {
576 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
577 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
578 }
579 }
580 return 0;
581}
582
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100583static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
584 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 int tram;
587 u32 val, addr;
588
589 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
590 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
591 set_bit(tram, icode->tram_valid);
592 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
593 if (!emu->audigy) {
594 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
595 } else {
596 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
597 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
598 }
599 if (put_user(val, &icode->tram_data_map[tram]) ||
600 put_user(addr, &icode->tram_addr_map[tram]))
601 return -EFAULT;
602 }
603 return 0;
604}
605
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100606static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
607 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 u32 pc, lo, hi;
610
611 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
612 if (!test_bit(pc / 2, icode->code_valid))
613 continue;
614 if (get_user(lo, &icode->code[pc + 0]) ||
615 get_user(hi, &icode->code[pc + 1]))
616 return -EFAULT;
617 snd_emu10k1_efx_write(emu, pc + 0, lo);
618 snd_emu10k1_efx_write(emu, pc + 1, hi);
619 }
620 return 0;
621}
622
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100623static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
624 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 u32 pc;
627
628 memset(icode->code_valid, 0, sizeof(icode->code_valid));
629 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
630 set_bit(pc / 2, icode->code_valid);
631 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
632 return -EFAULT;
633 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
634 return -EFAULT;
635 }
636 return 0;
637}
638
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100639static struct snd_emu10k1_fx8010_ctl *
640snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100642 struct snd_emu10k1_fx8010_ctl *ctl;
643 struct snd_kcontrol *kcontrol;
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200644
645 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 kcontrol = ctl->kcontrol;
647 if (kcontrol->id.iface == id->iface &&
648 !strcmp(kcontrol->id.name, id->name) &&
649 kcontrol->id.index == id->index)
650 return ctl;
651 }
652 return NULL;
653}
654
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100655#define MAX_TLV_SIZE 256
656
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100657static unsigned int *copy_tlv(const unsigned int __user *_tlv)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100658{
659 unsigned int data[2];
660 unsigned int *tlv;
661
662 if (!_tlv)
663 return NULL;
664 if (copy_from_user(data, _tlv, sizeof(data)))
665 return NULL;
666 if (data[1] >= MAX_TLV_SIZE)
667 return NULL;
Takashi Iwai6735e572008-01-19 10:33:07 +0100668 tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100669 if (!tlv)
670 return NULL;
671 memcpy(tlv, data, sizeof(data));
672 if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
673 kfree(tlv);
674 return NULL;
675 }
676 return tlv;
677}
678
679static int copy_gctl(struct snd_emu10k1 *emu,
680 struct snd_emu10k1_fx8010_control_gpr *gctl,
681 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
682 int idx)
683{
684 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
685
686 if (emu->support_tlv)
687 return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
688 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
689 if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
690 return -EFAULT;
691 gctl->tlv = NULL;
692 return 0;
693}
694
695static int copy_gctl_to_user(struct snd_emu10k1 *emu,
696 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
697 struct snd_emu10k1_fx8010_control_gpr *gctl,
698 int idx)
699{
700 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
701
702 if (emu->support_tlv)
703 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
704
705 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
706 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
707}
708
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100709static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
710 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711{
712 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100713 struct snd_ctl_elem_id __user *_id;
714 struct snd_ctl_elem_id id;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100715 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 int err;
717
718 for (i = 0, _id = icode->gpr_del_controls;
719 i < icode->gpr_del_control_count; i++, _id++) {
720 if (copy_from_user(&id, _id, sizeof(id)))
721 return -EFAULT;
722 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
723 return -ENOENT;
724 }
725 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
726 if (! gctl)
727 return -ENOMEM;
728 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100729 for (i = 0; i < icode->gpr_add_control_count; i++) {
730 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 err = -EFAULT;
732 goto __error;
733 }
734 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
735 continue;
736 down_read(&emu->card->controls_rwsem);
737 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
738 up_read(&emu->card->controls_rwsem);
739 err = -EEXIST;
740 goto __error;
741 }
742 up_read(&emu->card->controls_rwsem);
743 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
744 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
745 err = -EINVAL;
746 goto __error;
747 }
748 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100749 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* FIXME: we need to check the WRITE access */
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100751 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 err = -EFAULT;
753 goto __error;
754 }
755 }
756 __error:
757 kfree(gctl);
758 return err;
759}
760
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100761static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100763 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100765 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 kctl->private_value = 0;
767 list_del(&ctl->list);
768 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100769 if (kctl->tlv.p)
770 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100773static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
774 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100777 struct snd_emu10k1_fx8010_control_gpr *gctl;
778 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
779 struct snd_kcontrol_new knew;
780 struct snd_kcontrol *kctl;
781 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 int err = 0;
783
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100784 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
786 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
787 if (!val || !gctl || !nctl) {
788 err = -ENOMEM;
789 goto __error;
790 }
791
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100792 for (i = 0; i < icode->gpr_add_control_count; i++) {
793 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 err = -EFAULT;
795 goto __error;
796 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200797 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
798 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
799 err = -EINVAL;
800 goto __error;
801 }
802 if (! gctl->id.name[0]) {
803 err = -EINVAL;
804 goto __error;
805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
807 memset(&knew, 0, sizeof(knew));
808 knew.iface = gctl->id.iface;
809 knew.name = gctl->id.name;
810 knew.index = gctl->id.index;
811 knew.device = gctl->id.device;
812 knew.subdevice = gctl->id.subdevice;
813 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100814 knew.tlv.p = copy_tlv(gctl->tlv);
815 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100816 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
817 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 knew.get = snd_emu10k1_gpr_ctl_get;
819 knew.put = snd_emu10k1_gpr_ctl_put;
820 memset(nctl, 0, sizeof(*nctl));
821 nctl->vcount = gctl->vcount;
822 nctl->count = gctl->count;
823 for (j = 0; j < 32; j++) {
824 nctl->gpr[j] = gctl->gpr[j];
825 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
826 val->value.integer.value[j] = gctl->value[j];
827 }
828 nctl->min = gctl->min;
829 nctl->max = gctl->max;
830 nctl->translation = gctl->translation;
831 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100832 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if (ctl == NULL) {
834 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100835 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 goto __error;
837 }
838 knew.private_value = (unsigned long)ctl;
839 *ctl = *nctl;
840 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
841 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100842 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 goto __error;
844 }
845 kctl->private_free = snd_emu10k1_ctl_private_free;
846 ctl->kcontrol = kctl;
847 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
848 } else {
849 /* overwrite */
850 nctl->list = ctl->list;
851 nctl->kcontrol = ctl->kcontrol;
852 *ctl = *nctl;
853 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
854 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
855 }
856 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
857 }
858 __error:
859 kfree(nctl);
860 kfree(gctl);
861 kfree(val);
862 return err;
863}
864
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100865static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
866 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100869 struct snd_ctl_elem_id id;
870 struct snd_ctl_elem_id __user *_id;
871 struct snd_emu10k1_fx8010_ctl *ctl;
872 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
874 for (i = 0, _id = icode->gpr_del_controls;
875 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200876 if (copy_from_user(&id, _id, sizeof(id)))
877 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 down_write(&card->controls_rwsem);
879 ctl = snd_emu10k1_look_for_ctl(emu, &id);
880 if (ctl)
881 snd_ctl_remove(card, ctl->kcontrol);
882 up_write(&card->controls_rwsem);
883 }
884 return 0;
885}
886
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100887static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
888 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890 unsigned int i = 0, j;
891 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100892 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100893 struct snd_emu10k1_fx8010_ctl *ctl;
894 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
896 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
897 if (! gctl)
898 return -ENOMEM;
899
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200900 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100902 if (icode->gpr_list_controls &&
903 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 memset(gctl, 0, sizeof(*gctl));
905 id = &ctl->kcontrol->id;
906 gctl->id.iface = id->iface;
907 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
908 gctl->id.index = id->index;
909 gctl->id.device = id->device;
910 gctl->id.subdevice = id->subdevice;
911 gctl->vcount = ctl->vcount;
912 gctl->count = ctl->count;
913 for (j = 0; j < 32; j++) {
914 gctl->gpr[j] = ctl->gpr[j];
915 gctl->value[j] = ctl->value[j];
916 }
917 gctl->min = ctl->min;
918 gctl->max = ctl->max;
919 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100920 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
921 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 kfree(gctl);
923 return -EFAULT;
924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 i++;
926 }
927 }
928 icode->gpr_list_control_total = total;
929 kfree(gctl);
930 return 0;
931}
932
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100933static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
934 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
936 int err = 0;
937
Ingo Molnar62932df2006-01-16 16:34:20 +0100938 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
940 goto __error;
941 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
942 /* stop FX processor - this may be dangerous, but it's better to miss
943 some samples than generate wrong ones - [jk] */
944 if (emu->audigy)
945 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
946 else
947 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
948 /* ok, do the main job */
949 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
950 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
951 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
952 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
953 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
954 goto __error;
955 /* start FX processor when the DSP code is updated */
956 if (emu->audigy)
957 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
958 else
959 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
960 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100961 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 return err;
963}
964
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100965static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
966 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 int err;
969
Ingo Molnar62932df2006-01-16 16:34:20 +0100970 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
972 /* ok, do the main job */
973 err = snd_emu10k1_gpr_peek(emu, icode);
974 if (err >= 0)
975 err = snd_emu10k1_tram_peek(emu, icode);
976 if (err >= 0)
977 err = snd_emu10k1_code_peek(emu, icode);
978 if (err >= 0)
979 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100980 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return err;
982}
983
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100984static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
985 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
987 unsigned int i;
988 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100989 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
992 return -EINVAL;
993 if (ipcm->channels > 32)
994 return -EINVAL;
995 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100996 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 spin_lock_irq(&emu->reg_lock);
998 if (pcm->opened) {
999 err = -EBUSY;
1000 goto __error;
1001 }
1002 if (ipcm->channels == 0) { /* remove */
1003 pcm->valid = 0;
1004 } else {
1005 /* FIXME: we need to add universal code to the PCM transfer routine */
1006 if (ipcm->channels != 2) {
1007 err = -EINVAL;
1008 goto __error;
1009 }
1010 pcm->valid = 1;
1011 pcm->opened = 0;
1012 pcm->channels = ipcm->channels;
1013 pcm->tram_start = ipcm->tram_start;
1014 pcm->buffer_size = ipcm->buffer_size;
1015 pcm->gpr_size = ipcm->gpr_size;
1016 pcm->gpr_count = ipcm->gpr_count;
1017 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1018 pcm->gpr_ptr = ipcm->gpr_ptr;
1019 pcm->gpr_trigger = ipcm->gpr_trigger;
1020 pcm->gpr_running = ipcm->gpr_running;
1021 for (i = 0; i < pcm->channels; i++)
1022 pcm->etram[i] = ipcm->etram[i];
1023 }
1024 __error:
1025 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001026 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return err;
1028}
1029
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001030static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1031 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
1033 unsigned int i;
1034 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001035 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1038 return -EINVAL;
1039 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001040 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 spin_lock_irq(&emu->reg_lock);
1042 ipcm->channels = pcm->channels;
1043 ipcm->tram_start = pcm->tram_start;
1044 ipcm->buffer_size = pcm->buffer_size;
1045 ipcm->gpr_size = pcm->gpr_size;
1046 ipcm->gpr_ptr = pcm->gpr_ptr;
1047 ipcm->gpr_count = pcm->gpr_count;
1048 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1049 ipcm->gpr_trigger = pcm->gpr_trigger;
1050 ipcm->gpr_running = pcm->gpr_running;
1051 for (i = 0; i < pcm->channels; i++)
1052 ipcm->etram[i] = pcm->etram[i];
1053 ipcm->res1 = ipcm->res2 = 0;
1054 ipcm->pad = 0;
1055 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001056 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return err;
1058}
1059
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001060#define SND_EMU10K1_GPR_CONTROLS 44
1061#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1063#define SND_EMU10K1_CAPTURE_CHANNELS 4
1064
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001065static void __devinit
1066snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1067 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
1069 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1070 strcpy(ctl->id.name, name);
1071 ctl->vcount = ctl->count = 1;
1072 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1073 ctl->min = 0;
1074 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001075 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1077}
1078
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001079static void __devinit
1080snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1081 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082{
1083 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1084 strcpy(ctl->id.name, name);
1085 ctl->vcount = ctl->count = 2;
1086 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1087 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1088 ctl->min = 0;
1089 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001090 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1092}
1093
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001094static void __devinit
1095snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1096 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
1098 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1099 strcpy(ctl->id.name, name);
1100 ctl->vcount = ctl->count = 1;
1101 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1102 ctl->min = 0;
1103 ctl->max = 1;
1104 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1105}
1106
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001107static void __devinit
1108snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1109 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
1111 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1112 strcpy(ctl->id.name, name);
1113 ctl->vcount = ctl->count = 2;
1114 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1115 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1116 ctl->min = 0;
1117 ctl->max = 1;
1118 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1119}
1120
Pavel Hofman13d45702007-06-11 12:21:20 +02001121/*
1122 * Used for emu1010 - conversion from 32-bit capture inputs from HANA
1123 * to 2 x 16-bit registers in audigy - their values are read via DMA.
1124 * Conversion is performed by Audigy DSP instructions of FX8010.
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
Pavel Hofman13d45702007-06-11 12:21:20 +02001196 /* PCM front Playback Volume (independent from stereo mix)
1197 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
1198 * where gpr contains attenuation from corresponding mixer control
1199 * (snd_emu10k1_init_stereo_control)
1200 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1202 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1203 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1204 gpr += 2;
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001205
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 /* PCM Surround Playback (independent from stereo mix) */
1207 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1208 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1209 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1210 gpr += 2;
1211
1212 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001213 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1215 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1216 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1217 gpr += 2;
1218 }
1219
1220 /* PCM Center Playback (independent from stereo mix) */
1221 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1222 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1223 gpr++;
1224
1225 /* PCM LFE Playback (independent from stereo mix) */
1226 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1227 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1228 gpr++;
1229
1230 /*
1231 * Stereo Mix
1232 */
1233 /* Wave (PCM) Playback Volume (will be renamed later) */
1234 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1235 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1236 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1237 gpr += 2;
1238
1239 /* Synth Playback */
1240 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1241 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1242 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1243 gpr += 2;
1244
1245 /* Wave (PCM) Capture */
1246 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1247 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1248 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1249 gpr += 2;
1250
1251 /* Synth Capture */
1252 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1253 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1254 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1255 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 /*
1258 * inputs
1259 */
1260#define A_ADD_VOLUME_IN(var,vol,input) \
1261A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1262
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001263 /* emu1212 DSP 0 and DSP 1 Capture */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001264 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001265 if (emu->card_capabilities->ca0108_chip) {
1266 /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
1267 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
1268 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
1269 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
1270 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
1271 } else {
1272 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1273 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1274 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001275 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1276 gpr += 2;
1277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 /* AC'97 Playback Volume - used only for mic (renamed later) */
1279 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1280 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1281 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1282 gpr += 2;
1283 /* AC'97 Capture Volume - used only for mic */
1284 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1285 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1286 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1287 gpr += 2;
1288
1289 /* mic capture buffer */
1290 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1291
1292 /* Audigy CD Playback Volume */
1293 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1294 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1295 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001296 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 gpr, 0);
1298 gpr += 2;
1299 /* Audigy CD Capture Volume */
1300 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1301 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1302 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001303 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 gpr, 0);
1305 gpr += 2;
1306
1307 /* Optical SPDIF Playback Volume */
1308 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1309 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001310 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 gpr += 2;
1312 /* Optical SPDIF Capture Volume */
1313 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1314 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001315 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 gpr += 2;
1317
1318 /* Line2 Playback Volume */
1319 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1320 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1321 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001322 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 gpr, 0);
1324 gpr += 2;
1325 /* Line2 Capture Volume */
1326 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1327 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1328 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001329 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 gpr, 0);
1331 gpr += 2;
1332
1333 /* Philips ADC Playback Volume */
1334 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1335 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1336 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1337 gpr += 2;
1338 /* Philips ADC Capture Volume */
1339 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1340 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1341 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1342 gpr += 2;
1343
1344 /* Aux2 Playback Volume */
1345 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1346 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1347 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001348 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 gpr, 0);
1350 gpr += 2;
1351 /* Aux2 Capture Volume */
1352 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1353 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1354 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001355 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 gpr, 0);
1357 gpr += 2;
1358
1359 /* Stereo Mix Front Playback Volume */
1360 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1361 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1362 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1363 gpr += 2;
1364
1365 /* Stereo Mix Surround Playback */
1366 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1367 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1368 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1369 gpr += 2;
1370
1371 /* Stereo Mix Center Playback */
1372 /* Center = sub = Left/2 + Right/2 */
1373 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1374 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1375 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1376 gpr++;
1377
1378 /* Stereo Mix LFE Playback */
1379 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1380 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1381 gpr++;
1382
Lee Revell2b637da2005-03-30 13:51:18 +02001383 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 /* Stereo Mix Side Playback */
1385 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1386 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1387 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1388 gpr += 2;
1389 }
1390
1391 /*
1392 * outputs
1393 */
1394#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1395#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1396 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1397
1398#define _A_SWITCH(icode, ptr, dst, src, sw) \
1399 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1400#define A_SWITCH(icode, ptr, dst, src, sw) \
1401 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1402#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1403 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1404#define A_SWITCH_NEG(icode, ptr, dst, src) \
1405 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1406
1407
1408 /*
1409 * Process tone control
1410 */
1411 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1412 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1413 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 */
1414 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 */
1415 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1416 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 +02001417 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 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 */
1419 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 */
1420 }
1421
1422
1423 ctl = &controls[nctl + 0];
1424 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1425 strcpy(ctl->id.name, "Tone Control - Bass");
1426 ctl->vcount = 2;
1427 ctl->count = 10;
1428 ctl->min = 0;
1429 ctl->max = 40;
1430 ctl->value[0] = ctl->value[1] = 20;
1431 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1432 ctl = &controls[nctl + 1];
1433 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1434 strcpy(ctl->id.name, "Tone Control - Treble");
1435 ctl->vcount = 2;
1436 ctl->count = 10;
1437 ctl->min = 0;
1438 ctl->max = 40;
1439 ctl->value[0] = ctl->value[1] = 20;
1440 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1441
1442#define BASS_GPR 0x8c
1443#define TREBLE_GPR 0x96
1444
1445 for (z = 0; z < 5; z++) {
1446 int j;
1447 for (j = 0; j < 2; j++) {
1448 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1449 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1450 }
1451 }
1452 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1453 int j, k, l, d;
1454 for (j = 0; j < 2; j++) { /* left/right */
1455 k = 0xb0 + (z * 8) + (j * 4);
1456 l = 0xe0 + (z * 8) + (j * 4);
1457 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1458
1459 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1460 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1461 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1462 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1463 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1464 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1465
1466 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1467 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1468 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1469 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1470 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1471 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1472
1473 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1474
1475 if (z == 2) /* center */
1476 break;
1477 }
1478 }
1479 nctl += 2;
1480
1481#undef BASS_GPR
1482#undef TREBLE_GPR
1483
1484 for (z = 0; z < 8; z++) {
1485 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1486 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1487 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1488 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1489 }
1490 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1491 gpr += 2;
1492
1493 /* Master volume (will be renamed later) */
1494 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));
1495 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));
1496 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));
1497 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));
1498 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));
1499 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));
1500 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));
1501 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));
1502 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1503 gpr += 2;
1504
1505 /* analog speakers */
1506 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1507 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1508 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1509 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001510 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1512
1513 /* headphone */
1514 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1515
1516 /* digital outputs */
1517 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001518 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001519 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
1520 snd_printk("EMU outputs on\n");
1521 for (z = 0; z < 8; z++) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001522 if (emu->card_capabilities->ca0108_chip) {
1523 A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1524 } else {
1525 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1526 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001527 }
1528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 /* IEC958 Optical Raw Playback Switch */
1531 gpr_map[gpr++] = 0;
1532 gpr_map[gpr++] = 0x1008;
1533 gpr_map[gpr++] = 0xffff0000;
1534 for (z = 0; z < 2; z++) {
1535 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1536 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1537 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1538 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1539 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1540 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1541 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1542 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1543 /* 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 +02001544 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1546 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1547 } else {
1548 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1549 }
1550 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001551 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 -07001552 gpr += 2;
1553
1554 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1555 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1556 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1557
1558 /* ADC buffer */
1559#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1560 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1561#else
1562 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1563 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1564#endif
1565
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001566 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001567 if (emu->card_capabilities->ca0108_chip) {
1568 snd_printk("EMU2 inputs on\n");
1569 for (z = 0; z < 0x10; z++) {
1570 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
1571 bit_shifter16,
1572 A3_EMU32IN(z),
1573 A_FXBUS2(z*2) );
1574 }
1575 } else {
1576 snd_printk("EMU inputs on\n");
1577 /* Capture 16 (originally 8) channels of S32_LE sound */
1578
1579 /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
1580 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1581 /* A_P16VIN(0) is delayed by one sample,
1582 * so all other A_P16VIN channels will need to also be delayed
1583 */
1584 /* Left ADC in. 1 of 2 */
1585 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1586 /* Right ADC in 1 of 2 */
1587 gpr_map[gpr++] = 0x00000000;
1588 /* Delaying by one sample: instead of copying the input
1589 * value A_P16VIN to output A_FXBUS2 as in the first channel,
1590 * we use an auxiliary register, delaying the value by one
1591 * sample
1592 */
1593 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1594 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1595 gpr_map[gpr++] = 0x00000000;
1596 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1597 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
1598 gpr_map[gpr++] = 0x00000000;
1599 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
1600 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1601 /* For 96kHz mode */
1602 /* Left ADC in. 2 of 2 */
1603 gpr_map[gpr++] = 0x00000000;
1604 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1605 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1606 /* Right ADC in 2 of 2 */
1607 gpr_map[gpr++] = 0x00000000;
1608 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1609 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
1610 gpr_map[gpr++] = 0x00000000;
1611 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
1612 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
1613 gpr_map[gpr++] = 0x00000000;
1614 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
1615 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1616 /* Pavel Hofman - we still have voices, A_FXBUS2s, and
1617 * A_P16VINs available -
1618 * let's add 8 more capture channels - total of 16
1619 */
1620 gpr_map[gpr++] = 0x00000000;
1621 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1622 bit_shifter16,
1623 A_GPR(gpr - 1),
1624 A_FXBUS2(0x10));
1625 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
1626 A_C_00000000, A_C_00000000);
1627 gpr_map[gpr++] = 0x00000000;
1628 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1629 bit_shifter16,
1630 A_GPR(gpr - 1),
1631 A_FXBUS2(0x12));
1632 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
1633 A_C_00000000, A_C_00000000);
1634 gpr_map[gpr++] = 0x00000000;
1635 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1636 bit_shifter16,
1637 A_GPR(gpr - 1),
1638 A_FXBUS2(0x14));
1639 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
1640 A_C_00000000, A_C_00000000);
1641 gpr_map[gpr++] = 0x00000000;
1642 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1643 bit_shifter16,
1644 A_GPR(gpr - 1),
1645 A_FXBUS2(0x16));
1646 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
1647 A_C_00000000, A_C_00000000);
1648 gpr_map[gpr++] = 0x00000000;
1649 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1650 bit_shifter16,
1651 A_GPR(gpr - 1),
1652 A_FXBUS2(0x18));
1653 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
1654 A_C_00000000, A_C_00000000);
1655 gpr_map[gpr++] = 0x00000000;
1656 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1657 bit_shifter16,
1658 A_GPR(gpr - 1),
1659 A_FXBUS2(0x1a));
1660 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
1661 A_C_00000000, A_C_00000000);
1662 gpr_map[gpr++] = 0x00000000;
1663 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1664 bit_shifter16,
1665 A_GPR(gpr - 1),
1666 A_FXBUS2(0x1c));
1667 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
1668 A_C_00000000, A_C_00000000);
1669 gpr_map[gpr++] = 0x00000000;
1670 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1671 bit_shifter16,
1672 A_GPR(gpr - 1),
1673 A_FXBUS2(0x1e));
1674 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
1675 A_C_00000000, A_C_00000000);
1676 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001677
1678#if 0
1679 for (z = 4; z < 8; z++) {
1680 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1681 }
1682 for (z = 0xc; z < 0x10; z++) {
1683 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1684 }
1685#endif
1686 } else {
1687 /* EFX capture - capture the 16 EXTINs */
1688 /* Capture 16 channels of S16_LE sound */
1689 for (z = 0; z < 16; z++) {
1690 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 }
1693
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001694#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 /*
1696 * ok, set up done..
1697 */
1698
1699 if (gpr > tmp) {
1700 snd_BUG();
1701 err = -EIO;
1702 goto __err;
1703 }
1704 /* clear remaining instruction memory */
1705 while (ptr < 0x400)
1706 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1707
1708 seg = snd_enter_user();
1709 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001710 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001711 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001713 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 snd_leave_user(seg);
1715
1716 __err:
1717 kfree(controls);
1718 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001719 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 kfree(icode);
1721 }
1722 return err;
1723}
1724
1725
1726/*
1727 * initial DSP configuration for Emu10k1
1728 */
1729
1730/* when volume = max, then copy only to avoid volume modification */
1731/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001732static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733{
1734 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1735 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1736 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1737 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1738}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001739static 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 -07001740{
1741 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1742 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1743 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1744 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1745 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1746}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001747static 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 -07001748{
1749 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1750 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1751 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1752 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1753 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1754}
1755
1756#define VOLUME(icode, ptr, dst, src, vol) \
1757 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1758#define VOLUME_IN(icode, ptr, dst, src, vol) \
1759 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1760#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1761 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1762#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1763 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1764#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1765 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1766#define _SWITCH(icode, ptr, dst, src, sw) \
1767 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1768#define SWITCH(icode, ptr, dst, src, sw) \
1769 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1770#define SWITCH_IN(icode, ptr, dst, src, sw) \
1771 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1772#define _SWITCH_NEG(icode, ptr, dst, src) \
1773 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1774#define SWITCH_NEG(icode, ptr, dst, src) \
1775 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1776
1777
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001778static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779{
1780 int err, i, z, gpr, tmp, playback, capture;
1781 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001782 struct snd_emu10k1_fx8010_code *icode;
1783 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1784 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 u32 *gpr_map;
1786 mm_segment_t seg;
1787
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001788 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001790 if ((icode->gpr_map = (u_int32_t __user *)
1791 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1792 GFP_KERNEL)) == NULL ||
1793 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1794 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1795 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001796 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 err = -ENOMEM;
1798 goto __err;
1799 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001800 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802 icode->tram_data_map = icode->gpr_map + 256;
1803 icode->tram_addr_map = icode->tram_data_map + 160;
1804 icode->code = icode->tram_addr_map + 160;
1805
1806 /* clear free GPRs */
1807 for (i = 0; i < 256; i++)
1808 set_bit(i, icode->gpr_valid);
1809
1810 /* clear TRAM data & address lines */
1811 for (i = 0; i < 160; i++)
1812 set_bit(i, icode->tram_valid);
1813
1814 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1815 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001816 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 playback = SND_EMU10K1_INPUTS;
1818 /* we have 6 playback channels and tone control doubles */
1819 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1820 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1821 tmp = 0x88; /* we need 4 temporary GPR */
1822 /* from 0x8c to 0xff is the area for tone control */
1823
1824 /* stop FX processor */
1825 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1826
1827 /*
1828 * Process FX Buses
1829 */
1830 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1831 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1832 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1833 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1834 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1835 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1836 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1837 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1838 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1839 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001840 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1841 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843 /* Raw S/PDIF PCM */
1844 ipcm->substream = 0;
1845 ipcm->channels = 2;
1846 ipcm->tram_start = 0;
1847 ipcm->buffer_size = (64 * 1024) / 2;
1848 ipcm->gpr_size = gpr++;
1849 ipcm->gpr_ptr = gpr++;
1850 ipcm->gpr_count = gpr++;
1851 ipcm->gpr_tmpcount = gpr++;
1852 ipcm->gpr_trigger = gpr++;
1853 ipcm->gpr_running = gpr++;
1854 ipcm->etram[0] = 0;
1855 ipcm->etram[1] = 1;
1856
1857 gpr_map[gpr + 0] = 0xfffff000;
1858 gpr_map[gpr + 1] = 0xffff0000;
1859 gpr_map[gpr + 2] = 0x70000000;
1860 gpr_map[gpr + 3] = 0x00000007;
1861 gpr_map[gpr + 4] = 0x001f << 11;
1862 gpr_map[gpr + 5] = 0x001c << 11;
1863 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1864 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1865 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1866 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1867 gpr_map[gpr + 10] = 1<<11;
1868 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1869 gpr_map[gpr + 12] = 0;
1870
1871 /* if the trigger flag is not set, skip */
1872 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1873 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1874 /* if the running flag is set, we're running */
1875 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1876 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1877 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1878 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1879 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1880 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1881 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1882
1883 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1884 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1885 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1886 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1887
1888 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1889 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1890 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1891 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1892 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1893
1894 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1895 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1896 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1897 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1898 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1899
1900 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1901 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1902 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1903 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1904 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1905
1906 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1907 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1908 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1909 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1910 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1911
1912 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1913 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1914
1915 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1916 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1917
1918 /* 24: */
1919 gpr += 13;
1920
1921 /* Wave Playback Volume */
1922 for (z = 0; z < 2; z++)
1923 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1924 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1925 gpr += 2;
1926
1927 /* Wave Surround Playback Volume */
1928 for (z = 0; z < 2; z++)
1929 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1930 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1931 gpr += 2;
1932
1933 /* Wave Center/LFE Playback Volume */
1934 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1935 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1936 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1937 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1938 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1939 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1940
1941 /* Wave Capture Volume + Switch */
1942 for (z = 0; z < 2; z++) {
1943 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1944 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1945 }
1946 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1947 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1948 gpr += 4;
1949
1950 /* Synth Playback Volume */
1951 for (z = 0; z < 2; z++)
1952 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1953 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1954 gpr += 2;
1955
1956 /* Synth Capture Volume + Switch */
1957 for (z = 0; z < 2; z++) {
1958 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1959 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1960 }
1961 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1962 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1963 gpr += 4;
1964
1965 /* Surround Digital Playback Volume (renamed later without Digital) */
1966 for (z = 0; z < 2; z++)
1967 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1968 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1969 gpr += 2;
1970
1971 /* Surround Capture Volume + Switch */
1972 for (z = 0; z < 2; z++) {
1973 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1974 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1975 }
1976 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1977 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1978 gpr += 4;
1979
1980 /* Center Playback Volume (renamed later without Digital) */
1981 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1982 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1983
1984 /* LFE Playback Volume + Switch (renamed later without Digital) */
1985 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1986 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1987
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001988 /* Front Playback Volume */
1989 for (z = 0; z < 2; z++)
1990 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1991 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1992 gpr += 2;
1993
1994 /* Front Capture Volume + Switch */
1995 for (z = 0; z < 2; z++) {
1996 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1997 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1998 }
1999 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2000 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2001 gpr += 3;
2002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 /*
2004 * Process inputs
2005 */
2006
2007 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
2008 /* AC'97 Playback Volume */
2009 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
2010 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
2011 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
2012 /* AC'97 Capture Volume */
2013 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
2014 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
2015 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
2016 }
2017
2018 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
2019 /* IEC958 TTL Playback Volume */
2020 for (z = 0; z < 2; z++)
2021 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002022 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 gpr += 2;
2024
2025 /* IEC958 TTL Capture Volume + Switch */
2026 for (z = 0; z < 2; z++) {
2027 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
2028 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2029 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002030 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
2031 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 -07002032 gpr += 4;
2033 }
2034
2035 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
2036 /* Zoom Video Playback Volume */
2037 for (z = 0; z < 2; z++)
2038 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
2039 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
2040 gpr += 2;
2041
2042 /* Zoom Video Capture Volume + Switch */
2043 for (z = 0; z < 2; z++) {
2044 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
2045 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2046 }
2047 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
2048 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
2049 gpr += 4;
2050 }
2051
2052 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
2053 /* IEC958 Optical Playback Volume */
2054 for (z = 0; z < 2; z++)
2055 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002056 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 gpr += 2;
2058
2059 /* IEC958 Optical Capture Volume */
2060 for (z = 0; z < 2; z++) {
2061 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
2062 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2063 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002064 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
2065 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 -07002066 gpr += 4;
2067 }
2068
2069 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
2070 /* Line LiveDrive Playback Volume */
2071 for (z = 0; z < 2; z++)
2072 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
2073 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
2074 gpr += 2;
2075
2076 /* Line LiveDrive Capture Volume + Switch */
2077 for (z = 0; z < 2; z++) {
2078 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
2079 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2080 }
2081 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
2082 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
2083 gpr += 4;
2084 }
2085
2086 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
2087 /* IEC958 Coax Playback Volume */
2088 for (z = 0; z < 2; z++)
2089 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002090 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 gpr += 2;
2092
2093 /* IEC958 Coax Capture Volume + Switch */
2094 for (z = 0; z < 2; z++) {
2095 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2096 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2097 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002098 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2099 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 -07002100 gpr += 4;
2101 }
2102
2103 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2104 /* Line LiveDrive Playback Volume */
2105 for (z = 0; z < 2; z++)
2106 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2107 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2108 controls[i-1].id.index = 1;
2109 gpr += 2;
2110
2111 /* Line LiveDrive Capture Volume */
2112 for (z = 0; z < 2; z++) {
2113 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2114 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2115 }
2116 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2117 controls[i-1].id.index = 1;
2118 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2119 controls[i-1].id.index = 1;
2120 gpr += 4;
2121 }
2122
2123 /*
2124 * Process tone control
2125 */
2126 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2127 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2128 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2129 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2130 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2131 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2132
2133 ctl = &controls[i + 0];
2134 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2135 strcpy(ctl->id.name, "Tone Control - Bass");
2136 ctl->vcount = 2;
2137 ctl->count = 10;
2138 ctl->min = 0;
2139 ctl->max = 40;
2140 ctl->value[0] = ctl->value[1] = 20;
2141 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2142 ctl = &controls[i + 1];
2143 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2144 strcpy(ctl->id.name, "Tone Control - Treble");
2145 ctl->vcount = 2;
2146 ctl->count = 10;
2147 ctl->min = 0;
2148 ctl->max = 40;
2149 ctl->value[0] = ctl->value[1] = 20;
2150 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2151
2152#define BASS_GPR 0x8c
2153#define TREBLE_GPR 0x96
2154
2155 for (z = 0; z < 5; z++) {
2156 int j;
2157 for (j = 0; j < 2; j++) {
2158 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2159 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2160 }
2161 }
2162 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2163 int j, k, l, d;
2164 for (j = 0; j < 2; j++) { /* left/right */
2165 k = 0xa0 + (z * 8) + (j * 4);
2166 l = 0xd0 + (z * 8) + (j * 4);
2167 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2168
2169 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2170 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2171 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2172 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2173 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2174 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2175
2176 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2177 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2178 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2179 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2180 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2181 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2182
2183 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2184
2185 if (z == 2) /* center */
2186 break;
2187 }
2188 }
2189 i += 2;
2190
2191#undef BASS_GPR
2192#undef TREBLE_GPR
2193
2194 for (z = 0; z < 6; z++) {
2195 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2196 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2197 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2198 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2199 }
2200 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2201 gpr += 2;
2202
2203 /*
2204 * Process outputs
2205 */
2206 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2207 /* AC'97 Playback Volume */
2208
2209 for (z = 0; z < 2; z++)
2210 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2211 }
2212
2213 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2214 /* IEC958 Optical Raw Playback Switch */
2215
2216 for (z = 0; z < 2; z++) {
2217 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2218 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2219 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2220 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2221#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2222 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2223#endif
2224 }
2225
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002226 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 -07002227 gpr += 2;
2228 }
2229
2230 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2231 /* Headphone Playback Volume */
2232
2233 for (z = 0; z < 2; z++) {
2234 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2235 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2236 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2237 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2238 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2239 }
2240
2241 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2242 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2243 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2244 controls[i-1].id.index = 1;
2245 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2246 controls[i-1].id.index = 1;
2247
2248 gpr += 4;
2249 }
2250
2251 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2252 for (z = 0; z < 2; z++)
2253 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2254
2255 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2256 for (z = 0; z < 2; z++)
2257 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2258
2259 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2260#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2261 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2262 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2263#else
2264 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2265 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2266#endif
2267 }
2268
2269 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2270#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2271 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2272 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2273#else
2274 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2275 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2276#endif
2277 }
2278
2279#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2280 for (z = 0; z < 2; z++)
2281 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2282#endif
2283
2284 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2285 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2286
2287 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002288 if (emu->card_capabilities->sblive51) {
2289 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2290 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2291 *
2292 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2293 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2294 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2295 * channel. Multitrack recorders will still see the center/lfe output signal
2296 * on the second and third channels.
2297 */
2298 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2299 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2300 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2301 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2302 for (z = 4; z < 14; z++)
2303 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2304 } else {
2305 for (z = 0; z < 16; z++)
2306 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 }
Lee Revell2b637da2005-03-30 13:51:18 +02002308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 if (gpr > tmp) {
2311 snd_BUG();
2312 err = -EIO;
2313 goto __err;
2314 }
2315 if (i > SND_EMU10K1_GPR_CONTROLS) {
2316 snd_BUG();
2317 err = -EIO;
2318 goto __err;
2319 }
2320
2321 /* clear remaining instruction memory */
2322 while (ptr < 0x200)
2323 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2324
2325 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2326 goto __err;
2327 seg = snd_enter_user();
2328 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002329 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002330 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002332 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 snd_leave_user(seg);
2334 if (err >= 0)
2335 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2336 __err:
2337 kfree(ipcm);
2338 kfree(controls);
2339 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002340 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 kfree(icode);
2342 }
2343 return err;
2344}
2345
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002346int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347{
Takashi Iwai09668b42005-11-17 16:14:10 +01002348 spin_lock_init(&emu->fx8010.irq_lock);
2349 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 if (emu->audigy)
2351 return _snd_emu10k1_audigy_init_efx(emu);
2352 else
2353 return _snd_emu10k1_init_efx(emu);
2354}
2355
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002356void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
2358 /* stop processor */
2359 if (emu->audigy)
2360 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2361 else
2362 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2363}
2364
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002365#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002366int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002368 if (output < 0 || output >= 6)
2369 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2371 return 0;
2372}
2373
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002374int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002376 if (output < 0 || output >= 6)
2377 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2379 return 0;
2380}
2381#endif
2382
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002383int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384{
2385 u8 size_reg = 0;
2386
2387 /* size is in samples */
2388 if (size != 0) {
2389 size = (size - 1) >> 13;
2390
2391 while (size) {
2392 size >>= 1;
2393 size_reg++;
2394 }
2395 size = 0x2000 << size_reg;
2396 }
2397 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2398 return 0;
2399 spin_lock_irq(&emu->emu_lock);
2400 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2401 spin_unlock_irq(&emu->emu_lock);
2402 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2403 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2404 if (emu->fx8010.etram_pages.area != NULL) {
2405 snd_dma_free_pages(&emu->fx8010.etram_pages);
2406 emu->fx8010.etram_pages.area = NULL;
2407 emu->fx8010.etram_pages.bytes = 0;
2408 }
2409
2410 if (size > 0) {
2411 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2412 size * 2, &emu->fx8010.etram_pages) < 0)
2413 return -ENOMEM;
2414 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2415 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2416 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2417 spin_lock_irq(&emu->emu_lock);
2418 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002419 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 }
2421
2422 return 0;
2423}
2424
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002425static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
2427 return 0;
2428}
2429
2430static void copy_string(char *dst, char *src, char *null, int idx)
2431{
2432 if (src == NULL)
2433 sprintf(dst, "%s %02X", null, idx);
2434 else
2435 strcpy(dst, src);
2436}
2437
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002438static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002439 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
2441 char **fxbus, **extin, **extout;
2442 unsigned short fxbus_mask, extin_mask, extout_mask;
2443 int res;
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 info->internal_tram_size = emu->fx8010.itram_size;
2446 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2447 fxbus = fxbuses;
2448 extin = emu->audigy ? audigy_ins : creative_ins;
2449 extout = emu->audigy ? audigy_outs : creative_outs;
2450 fxbus_mask = emu->fx8010.fxbus_mask;
2451 extin_mask = emu->fx8010.extin_mask;
2452 extout_mask = emu->fx8010.extout_mask;
2453 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2454 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2455 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2456 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2457 }
2458 for (res = 16; res < 32; res++, extout++)
2459 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2460 info->gpr_controls = emu->fx8010.gpr_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461}
2462
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002463static 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 -07002464{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002465 struct snd_emu10k1 *emu = hw->private_data;
2466 struct snd_emu10k1_fx8010_info *info;
2467 struct snd_emu10k1_fx8010_code *icode;
2468 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 unsigned int addr;
2470 void __user *argp = (void __user *)arg;
2471 int res;
2472
2473 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002474 case SNDRV_EMU10K1_IOCTL_PVERSION:
2475 emu->support_tlv = 1;
2476 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002478 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (!info)
2480 return -ENOMEM;
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002481 snd_emu10k1_fx8010_info(emu, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 if (copy_to_user(argp, info, sizeof(*info))) {
2483 kfree(info);
2484 return -EFAULT;
2485 }
2486 kfree(info);
2487 return 0;
2488 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2489 if (!capable(CAP_SYS_ADMIN))
2490 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002491 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (icode == NULL)
2493 return -ENOMEM;
2494 if (copy_from_user(icode, argp, sizeof(*icode))) {
2495 kfree(icode);
2496 return -EFAULT;
2497 }
2498 res = snd_emu10k1_icode_poke(emu, icode);
2499 kfree(icode);
2500 return res;
2501 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002502 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 if (icode == NULL)
2504 return -ENOMEM;
2505 if (copy_from_user(icode, argp, sizeof(*icode))) {
2506 kfree(icode);
2507 return -EFAULT;
2508 }
2509 res = snd_emu10k1_icode_peek(emu, icode);
2510 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2511 kfree(icode);
2512 return -EFAULT;
2513 }
2514 kfree(icode);
2515 return res;
2516 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002517 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 if (ipcm == NULL)
2519 return -ENOMEM;
2520 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2521 kfree(ipcm);
2522 return -EFAULT;
2523 }
2524 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2525 kfree(ipcm);
2526 return res;
2527 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002528 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 if (ipcm == NULL)
2530 return -ENOMEM;
2531 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2532 kfree(ipcm);
2533 return -EFAULT;
2534 }
2535 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2536 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2537 kfree(ipcm);
2538 return -EFAULT;
2539 }
2540 kfree(ipcm);
2541 return res;
2542 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2543 if (!capable(CAP_SYS_ADMIN))
2544 return -EPERM;
2545 if (get_user(addr, (unsigned int __user *)argp))
2546 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002547 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002549 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 return res;
2551 case SNDRV_EMU10K1_IOCTL_STOP:
2552 if (!capable(CAP_SYS_ADMIN))
2553 return -EPERM;
2554 if (emu->audigy)
2555 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2556 else
2557 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2558 return 0;
2559 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2560 if (!capable(CAP_SYS_ADMIN))
2561 return -EPERM;
2562 if (emu->audigy)
2563 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2564 else
2565 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2566 return 0;
2567 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2568 if (!capable(CAP_SYS_ADMIN))
2569 return -EPERM;
2570 if (emu->audigy)
2571 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2572 else
2573 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2574 udelay(10);
2575 if (emu->audigy)
2576 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2577 else
2578 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2579 return 0;
2580 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2581 if (!capable(CAP_SYS_ADMIN))
2582 return -EPERM;
2583 if (get_user(addr, (unsigned int __user *)argp))
2584 return -EFAULT;
2585 if (addr > 0x1ff)
2586 return -EINVAL;
2587 if (emu->audigy)
2588 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2589 else
2590 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2591 udelay(10);
2592 if (emu->audigy)
2593 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2594 else
2595 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2596 return 0;
2597 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2598 if (emu->audigy)
2599 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2600 else
2601 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2602 if (put_user(addr, (unsigned int __user *)argp))
2603 return -EFAULT;
2604 return 0;
2605 }
2606 return -ENOTTY;
2607}
2608
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002609static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
2611 return 0;
2612}
2613
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002614int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002616 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 int err;
2618
2619 if (rhwdep)
2620 *rhwdep = NULL;
2621 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2622 return err;
2623 strcpy(hw->name, "EMU10K1 (FX8010)");
2624 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2625 hw->ops.open = snd_emu10k1_fx8010_open;
2626 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2627 hw->ops.release = snd_emu10k1_fx8010_release;
2628 hw->private_data = emu;
2629 if (rhwdep)
2630 *rhwdep = hw;
2631 return 0;
2632}
Takashi Iwai09668b42005-11-17 16:14:10 +01002633
2634#ifdef CONFIG_PM
2635int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2636{
2637 int len;
2638
2639 len = emu->audigy ? 0x200 : 0x100;
2640 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2641 if (! emu->saved_gpr)
2642 return -ENOMEM;
2643 len = emu->audigy ? 0x100 : 0xa0;
2644 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2645 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2646 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2647 return -ENOMEM;
2648 len = emu->audigy ? 2 * 1024 : 2 * 512;
2649 emu->saved_icode = vmalloc(len * 4);
2650 if (! emu->saved_icode)
2651 return -ENOMEM;
2652 return 0;
2653}
2654
2655void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2656{
2657 kfree(emu->saved_gpr);
2658 kfree(emu->tram_val_saved);
2659 kfree(emu->tram_addr_saved);
2660 vfree(emu->saved_icode);
2661}
2662
2663/*
2664 * save/restore GPR, TRAM and codes
2665 */
2666void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2667{
2668 int i, len;
2669
2670 len = emu->audigy ? 0x200 : 0x100;
2671 for (i = 0; i < len; i++)
2672 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2673
2674 len = emu->audigy ? 0x100 : 0xa0;
2675 for (i = 0; i < len; i++) {
2676 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2677 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2678 if (emu->audigy) {
2679 emu->tram_addr_saved[i] >>= 12;
2680 emu->tram_addr_saved[i] |=
2681 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2682 }
2683 }
2684
2685 len = emu->audigy ? 2 * 1024 : 2 * 512;
2686 for (i = 0; i < len; i++)
2687 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2688}
2689
2690void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2691{
2692 int i, len;
2693
2694 /* set up TRAM */
2695 if (emu->fx8010.etram_pages.bytes > 0) {
2696 unsigned size, size_reg = 0;
2697 size = emu->fx8010.etram_pages.bytes / 2;
2698 size = (size - 1) >> 13;
2699 while (size) {
2700 size >>= 1;
2701 size_reg++;
2702 }
2703 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2704 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2705 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2706 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2707 }
2708
2709 if (emu->audigy)
2710 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2711 else
2712 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2713
2714 len = emu->audigy ? 0x200 : 0x100;
2715 for (i = 0; i < len; i++)
2716 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2717
2718 len = emu->audigy ? 0x100 : 0xa0;
2719 for (i = 0; i < len; i++) {
2720 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2721 emu->tram_val_saved[i]);
2722 if (! emu->audigy)
2723 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2724 emu->tram_addr_saved[i]);
2725 else {
2726 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2727 emu->tram_addr_saved[i] << 12);
2728 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2729 emu->tram_addr_saved[i] >> 20);
2730 }
2731 }
2732
2733 len = emu->audigy ? 2 * 1024 : 2 * 512;
2734 for (i = 0; i < len; i++)
2735 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2736
2737 /* start FX processor when the DSP code is updated */
2738 if (emu->audigy)
2739 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2740 else
2741 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2742}
2743#endif