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