blob: 7dba08f0ab8e2c9d9e166fd12f3ed9934ed3cd34 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02002 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Creative Labs, Inc.
4 * Routines for effect processor FX8010
5 *
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01006 * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
7 * Added EMU 1010 support.
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * BUGS:
10 * --
11 *
12 * TODO:
13 * --
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 */
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/pci.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/delay.h>
34#include <linux/slab.h>
Andreas Schwabbd01e7b2005-12-05 15:12:20 +010035#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/init.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010037#include <linux/mutex.h>
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <sound/core.h>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010040#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <sound/emu10k1.h>
42
43#if 0 /* for testing purposes - digital out -> capture */
44#define EMU10K1_CAPTURE_DIGITAL_OUT
45#endif
46#if 0 /* for testing purposes - set S/PDIF to AC3 output */
47#define EMU10K1_SET_AC3_IEC958
48#endif
49#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
50#define EMU10K1_CENTER_LFE_FROM_FRONT
51#endif
52
53/*
54 * Tables
55 */
56
57static char *fxbuses[16] = {
58 /* 0x00 */ "PCM Left",
59 /* 0x01 */ "PCM Right",
60 /* 0x02 */ "PCM Surround Left",
61 /* 0x03 */ "PCM Surround Right",
62 /* 0x04 */ "MIDI Left",
63 /* 0x05 */ "MIDI Right",
64 /* 0x06 */ "Center",
65 /* 0x07 */ "LFE",
66 /* 0x08 */ NULL,
67 /* 0x09 */ NULL,
68 /* 0x0a */ NULL,
69 /* 0x0b */ NULL,
70 /* 0x0c */ "MIDI Reverb",
71 /* 0x0d */ "MIDI Chorus",
72 /* 0x0e */ NULL,
73 /* 0x0f */ NULL
74};
75
76static char *creative_ins[16] = {
77 /* 0x00 */ "AC97 Left",
78 /* 0x01 */ "AC97 Right",
79 /* 0x02 */ "TTL IEC958 Left",
80 /* 0x03 */ "TTL IEC958 Right",
81 /* 0x04 */ "Zoom Video Left",
82 /* 0x05 */ "Zoom Video Right",
83 /* 0x06 */ "Optical IEC958 Left",
84 /* 0x07 */ "Optical IEC958 Right",
85 /* 0x08 */ "Line/Mic 1 Left",
86 /* 0x09 */ "Line/Mic 1 Right",
87 /* 0x0a */ "Coaxial IEC958 Left",
88 /* 0x0b */ "Coaxial IEC958 Right",
89 /* 0x0c */ "Line/Mic 2 Left",
90 /* 0x0d */ "Line/Mic 2 Right",
91 /* 0x0e */ NULL,
92 /* 0x0f */ NULL
93};
94
95static char *audigy_ins[16] = {
96 /* 0x00 */ "AC97 Left",
97 /* 0x01 */ "AC97 Right",
98 /* 0x02 */ "Audigy CD Left",
99 /* 0x03 */ "Audigy CD Right",
100 /* 0x04 */ "Optical IEC958 Left",
101 /* 0x05 */ "Optical IEC958 Right",
102 /* 0x06 */ NULL,
103 /* 0x07 */ NULL,
104 /* 0x08 */ "Line/Mic 2 Left",
105 /* 0x09 */ "Line/Mic 2 Right",
106 /* 0x0a */ "SPDIF Left",
107 /* 0x0b */ "SPDIF Right",
108 /* 0x0c */ "Aux2 Left",
109 /* 0x0d */ "Aux2 Right",
110 /* 0x0e */ NULL,
111 /* 0x0f */ NULL
112};
113
114static char *creative_outs[32] = {
115 /* 0x00 */ "AC97 Left",
116 /* 0x01 */ "AC97 Right",
117 /* 0x02 */ "Optical IEC958 Left",
118 /* 0x03 */ "Optical IEC958 Right",
119 /* 0x04 */ "Center",
120 /* 0x05 */ "LFE",
121 /* 0x06 */ "Headphone Left",
122 /* 0x07 */ "Headphone Right",
123 /* 0x08 */ "Surround Left",
124 /* 0x09 */ "Surround Right",
125 /* 0x0a */ "PCM Capture Left",
126 /* 0x0b */ "PCM Capture Right",
127 /* 0x0c */ "MIC Capture",
128 /* 0x0d */ "AC97 Surround Left",
129 /* 0x0e */ "AC97 Surround Right",
130 /* 0x0f */ NULL,
131 /* 0x10 */ NULL,
132 /* 0x11 */ "Analog Center",
133 /* 0x12 */ "Analog LFE",
134 /* 0x13 */ NULL,
135 /* 0x14 */ NULL,
136 /* 0x15 */ NULL,
137 /* 0x16 */ NULL,
138 /* 0x17 */ NULL,
139 /* 0x18 */ NULL,
140 /* 0x19 */ NULL,
141 /* 0x1a */ NULL,
142 /* 0x1b */ NULL,
143 /* 0x1c */ NULL,
144 /* 0x1d */ NULL,
145 /* 0x1e */ NULL,
146 /* 0x1f */ NULL,
147};
148
149static char *audigy_outs[32] = {
150 /* 0x00 */ "Digital Front Left",
151 /* 0x01 */ "Digital Front Right",
152 /* 0x02 */ "Digital Center",
153 /* 0x03 */ "Digital LEF",
154 /* 0x04 */ "Headphone Left",
155 /* 0x05 */ "Headphone Right",
156 /* 0x06 */ "Digital Rear Left",
157 /* 0x07 */ "Digital Rear Right",
158 /* 0x08 */ "Front Left",
159 /* 0x09 */ "Front Right",
160 /* 0x0a */ "Center",
161 /* 0x0b */ "LFE",
162 /* 0x0c */ NULL,
163 /* 0x0d */ NULL,
164 /* 0x0e */ "Rear Left",
165 /* 0x0f */ "Rear Right",
166 /* 0x10 */ "AC97 Front Left",
167 /* 0x11 */ "AC97 Front Right",
168 /* 0x12 */ "ADC Caputre Left",
169 /* 0x13 */ "ADC Capture Right",
170 /* 0x14 */ NULL,
171 /* 0x15 */ NULL,
172 /* 0x16 */ NULL,
173 /* 0x17 */ NULL,
174 /* 0x18 */ NULL,
175 /* 0x19 */ NULL,
176 /* 0x1a */ NULL,
177 /* 0x1b */ NULL,
178 /* 0x1c */ NULL,
179 /* 0x1d */ NULL,
180 /* 0x1e */ NULL,
181 /* 0x1f */ NULL,
182};
183
184static const u32 bass_table[41][5] = {
185 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
186 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
187 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
188 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
189 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
190 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
191 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
192 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
193 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
194 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
195 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
196 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
197 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
198 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
199 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
200 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
201 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
202 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
203 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
204 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
205 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
206 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
207 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
208 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
209 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
210 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
211 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
212 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
213 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
214 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
215 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
216 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
217 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
218 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
219 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
220 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
221 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
222 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
223 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
224 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
225 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
226};
227
228static const u32 treble_table[41][5] = {
229 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
230 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
231 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
232 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
233 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
234 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
235 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
236 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
237 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
238 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
239 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
240 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
241 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
242 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
243 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
244 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
245 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
246 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
247 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
248 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
249 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
250 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
251 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
252 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
253 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
254 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
255 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
256 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
257 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
258 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
259 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
260 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
261 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
262 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
263 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
264 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
265 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
266 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
267 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
268 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
269 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
270};
271
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100272/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273static const u32 db_table[101] = {
274 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
275 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
276 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
277 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
278 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
279 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
280 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
281 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
282 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
283 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
284 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
285 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
286 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
287 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
288 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
289 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
290 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
291 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
292 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
293 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
294 0x7fffffff,
295};
296
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100297/* EMU10k1/EMU10k2 DSP control db gain */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100298static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300static const u32 onoff_table[2] = {
301 0x00000000, 0x00000001
302};
303
304/*
305 */
306
307static inline mm_segment_t snd_enter_user(void)
308{
309 mm_segment_t fs = get_fs();
310 set_fs(get_ds());
311 return fs;
312}
313
314static inline void snd_leave_user(mm_segment_t fs)
315{
316 set_fs(fs);
317}
318
319/*
320 * controls
321 */
322
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100323static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100325 struct snd_emu10k1_fx8010_ctl *ctl =
326 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 if (ctl->min == 0 && ctl->max == 1)
329 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
330 else
331 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
332 uinfo->count = ctl->vcount;
333 uinfo->value.integer.min = ctl->min;
334 uinfo->value.integer.max = ctl->max;
335 return 0;
336}
337
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100338static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100340 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
341 struct snd_emu10k1_fx8010_ctl *ctl =
342 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 unsigned long flags;
344 unsigned int i;
345
346 spin_lock_irqsave(&emu->reg_lock, flags);
347 for (i = 0; i < ctl->vcount; i++)
348 ucontrol->value.integer.value[i] = ctl->value[i];
349 spin_unlock_irqrestore(&emu->reg_lock, flags);
350 return 0;
351}
352
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100353static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100355 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
356 struct snd_emu10k1_fx8010_ctl *ctl =
357 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 unsigned long flags;
359 unsigned int nval, val;
360 unsigned int i, j;
361 int change = 0;
362
363 spin_lock_irqsave(&emu->reg_lock, flags);
364 for (i = 0; i < ctl->vcount; i++) {
365 nval = ucontrol->value.integer.value[i];
366 if (nval < ctl->min)
367 nval = ctl->min;
368 if (nval > ctl->max)
369 nval = ctl->max;
370 if (nval != ctl->value[i])
371 change = 1;
372 val = ctl->value[i] = nval;
373 switch (ctl->translation) {
374 case EMU10K1_GPR_TRANSLATION_NONE:
375 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
376 break;
377 case EMU10K1_GPR_TRANSLATION_TABLE100:
378 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
379 break;
380 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200381 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
382 change = -EIO;
383 goto __error;
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 for (j = 0; j < 5; j++)
386 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
387 break;
388 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200389 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
390 change = -EIO;
391 goto __error;
392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 for (j = 0; j < 5; j++)
394 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
395 break;
396 case EMU10K1_GPR_TRANSLATION_ONOFF:
397 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
398 break;
399 }
400 }
401 __error:
402 spin_unlock_irqrestore(&emu->reg_lock, flags);
403 return change;
404}
405
406/*
407 * Interrupt handler
408 */
409
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100410static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100412 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 irq = emu->fx8010.irq_handlers;
415 while (irq) {
416 nirq = irq->next; /* irq ptr can be removed from list */
417 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
418 if (irq->handler)
419 irq->handler(emu, irq->private_data);
420 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
421 }
422 irq = nirq;
423 }
424}
425
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100426int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
427 snd_fx8010_irq_handler_t *handler,
428 unsigned char gpr_running,
429 void *private_data,
430 struct snd_emu10k1_fx8010_irq **r_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100432 struct snd_emu10k1_fx8010_irq *irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 unsigned long flags;
434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 irq = kmalloc(sizeof(*irq), GFP_ATOMIC);
436 if (irq == NULL)
437 return -ENOMEM;
438 irq->handler = handler;
439 irq->gpr_running = gpr_running;
440 irq->private_data = private_data;
441 irq->next = NULL;
442 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
443 if (emu->fx8010.irq_handlers == NULL) {
444 emu->fx8010.irq_handlers = irq;
445 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
446 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
447 } else {
448 irq->next = emu->fx8010.irq_handlers;
449 emu->fx8010.irq_handlers = irq;
450 }
451 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
452 if (r_irq)
453 *r_irq = irq;
454 return 0;
455}
456
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100457int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
458 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100460 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 unsigned long flags;
462
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
464 if ((tmp = emu->fx8010.irq_handlers) == irq) {
465 emu->fx8010.irq_handlers = tmp->next;
466 if (emu->fx8010.irq_handlers == NULL) {
467 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
468 emu->dsp_interrupt = NULL;
469 }
470 } else {
471 while (tmp && tmp->next != irq)
472 tmp = tmp->next;
473 if (tmp)
474 tmp->next = tmp->next->next;
475 }
476 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
477 kfree(irq);
478 return 0;
479}
480
481/*************************************************************************
482 * EMU10K1 effect manager
483 *************************************************************************/
484
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100485static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
486 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 u32 op, u32 r, u32 a, u32 x, u32 y)
488{
489 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200490 if (snd_BUG_ON(*ptr >= 512))
491 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;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200507 if (snd_BUG_ON(*ptr >= 1024))
508 return;
Clemens Ladisch4d233592005-09-05 10:35:20 +0200509 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 set_bit(*ptr, icode->code_valid);
511 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
512 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
513 (*ptr)++;
514}
515
516#define A_OP(icode, ptr, op, r, a, x, y) \
517 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
518
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100519static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520{
521 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
522 snd_emu10k1_ptr_write(emu, pc, 0, data);
523}
524
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100525unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
527 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
528 return snd_emu10k1_ptr_read(emu, pc, 0);
529}
530
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100531static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
532 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533{
534 int gpr;
535 u32 val;
536
537 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
538 if (!test_bit(gpr, icode->gpr_valid))
539 continue;
540 if (get_user(val, &icode->gpr_map[gpr]))
541 return -EFAULT;
542 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
543 }
544 return 0;
545}
546
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100547static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
548 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
550 int gpr;
551 u32 val;
552
553 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
554 set_bit(gpr, icode->gpr_valid);
555 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
556 if (put_user(val, &icode->gpr_map[gpr]))
557 return -EFAULT;
558 }
559 return 0;
560}
561
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100562static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
563 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 int tram;
566 u32 addr, val;
567
568 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
569 if (!test_bit(tram, icode->tram_valid))
570 continue;
571 if (get_user(val, &icode->tram_data_map[tram]) ||
572 get_user(addr, &icode->tram_addr_map[tram]))
573 return -EFAULT;
574 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
575 if (!emu->audigy) {
576 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
577 } else {
578 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
579 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
580 }
581 }
582 return 0;
583}
584
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100585static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
586 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
588 int tram;
589 u32 val, addr;
590
591 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
592 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
593 set_bit(tram, icode->tram_valid);
594 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
595 if (!emu->audigy) {
596 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
597 } else {
598 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
599 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
600 }
601 if (put_user(val, &icode->tram_data_map[tram]) ||
602 put_user(addr, &icode->tram_addr_map[tram]))
603 return -EFAULT;
604 }
605 return 0;
606}
607
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100608static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
609 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 u32 pc, lo, hi;
612
613 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
614 if (!test_bit(pc / 2, icode->code_valid))
615 continue;
616 if (get_user(lo, &icode->code[pc + 0]) ||
617 get_user(hi, &icode->code[pc + 1]))
618 return -EFAULT;
619 snd_emu10k1_efx_write(emu, pc + 0, lo);
620 snd_emu10k1_efx_write(emu, pc + 1, hi);
621 }
622 return 0;
623}
624
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100625static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
626 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
628 u32 pc;
629
630 memset(icode->code_valid, 0, sizeof(icode->code_valid));
631 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
632 set_bit(pc / 2, icode->code_valid);
633 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
634 return -EFAULT;
635 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
636 return -EFAULT;
637 }
638 return 0;
639}
640
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100641static struct snd_emu10k1_fx8010_ctl *
642snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100644 struct snd_emu10k1_fx8010_ctl *ctl;
645 struct snd_kcontrol *kcontrol;
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200646
647 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 kcontrol = ctl->kcontrol;
649 if (kcontrol->id.iface == id->iface &&
650 !strcmp(kcontrol->id.name, id->name) &&
651 kcontrol->id.index == id->index)
652 return ctl;
653 }
654 return NULL;
655}
656
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100657#define MAX_TLV_SIZE 256
658
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100659static unsigned int *copy_tlv(const unsigned int __user *_tlv)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100660{
661 unsigned int data[2];
662 unsigned int *tlv;
663
664 if (!_tlv)
665 return NULL;
666 if (copy_from_user(data, _tlv, sizeof(data)))
667 return NULL;
668 if (data[1] >= MAX_TLV_SIZE)
669 return NULL;
Takashi Iwai6735e572008-01-19 10:33:07 +0100670 tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100671 if (!tlv)
672 return NULL;
673 memcpy(tlv, data, sizeof(data));
674 if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
675 kfree(tlv);
676 return NULL;
677 }
678 return tlv;
679}
680
681static int copy_gctl(struct snd_emu10k1 *emu,
682 struct snd_emu10k1_fx8010_control_gpr *gctl,
683 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
684 int idx)
685{
686 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
687
688 if (emu->support_tlv)
689 return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
690 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
691 if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
692 return -EFAULT;
693 gctl->tlv = NULL;
694 return 0;
695}
696
697static int copy_gctl_to_user(struct snd_emu10k1 *emu,
698 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
699 struct snd_emu10k1_fx8010_control_gpr *gctl,
700 int idx)
701{
702 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
703
704 if (emu->support_tlv)
705 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
706
707 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
708 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
709}
710
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100711static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
712 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100715 struct snd_ctl_elem_id __user *_id;
716 struct snd_ctl_elem_id id;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100717 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 int err;
719
720 for (i = 0, _id = icode->gpr_del_controls;
721 i < icode->gpr_del_control_count; i++, _id++) {
722 if (copy_from_user(&id, _id, sizeof(id)))
723 return -EFAULT;
724 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
725 return -ENOENT;
726 }
727 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
728 if (! gctl)
729 return -ENOMEM;
730 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100731 for (i = 0; i < icode->gpr_add_control_count; i++) {
732 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 err = -EFAULT;
734 goto __error;
735 }
736 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
737 continue;
738 down_read(&emu->card->controls_rwsem);
739 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
740 up_read(&emu->card->controls_rwsem);
741 err = -EEXIST;
742 goto __error;
743 }
744 up_read(&emu->card->controls_rwsem);
745 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
746 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
747 err = -EINVAL;
748 goto __error;
749 }
750 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100751 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 /* FIXME: we need to check the WRITE access */
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100753 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 err = -EFAULT;
755 goto __error;
756 }
757 }
758 __error:
759 kfree(gctl);
760 return err;
761}
762
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100763static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100765 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100767 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 kctl->private_value = 0;
769 list_del(&ctl->list);
770 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100771 if (kctl->tlv.p)
772 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773}
774
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100775static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
776 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
778 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100779 struct snd_emu10k1_fx8010_control_gpr *gctl;
780 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
781 struct snd_kcontrol_new knew;
782 struct snd_kcontrol *kctl;
783 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 int err = 0;
785
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100786 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
788 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
789 if (!val || !gctl || !nctl) {
790 err = -ENOMEM;
791 goto __error;
792 }
793
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100794 for (i = 0; i < icode->gpr_add_control_count; i++) {
795 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 err = -EFAULT;
797 goto __error;
798 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200799 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
800 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
801 err = -EINVAL;
802 goto __error;
803 }
804 if (! gctl->id.name[0]) {
805 err = -EINVAL;
806 goto __error;
807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
809 memset(&knew, 0, sizeof(knew));
810 knew.iface = gctl->id.iface;
811 knew.name = gctl->id.name;
812 knew.index = gctl->id.index;
813 knew.device = gctl->id.device;
814 knew.subdevice = gctl->id.subdevice;
815 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100816 knew.tlv.p = copy_tlv(gctl->tlv);
817 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100818 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
819 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 knew.get = snd_emu10k1_gpr_ctl_get;
821 knew.put = snd_emu10k1_gpr_ctl_put;
822 memset(nctl, 0, sizeof(*nctl));
823 nctl->vcount = gctl->vcount;
824 nctl->count = gctl->count;
825 for (j = 0; j < 32; j++) {
826 nctl->gpr[j] = gctl->gpr[j];
827 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
828 val->value.integer.value[j] = gctl->value[j];
829 }
830 nctl->min = gctl->min;
831 nctl->max = gctl->max;
832 nctl->translation = gctl->translation;
833 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100834 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (ctl == NULL) {
836 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100837 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 goto __error;
839 }
840 knew.private_value = (unsigned long)ctl;
841 *ctl = *nctl;
842 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
843 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100844 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 goto __error;
846 }
847 kctl->private_free = snd_emu10k1_ctl_private_free;
848 ctl->kcontrol = kctl;
849 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
850 } else {
851 /* overwrite */
852 nctl->list = ctl->list;
853 nctl->kcontrol = ctl->kcontrol;
854 *ctl = *nctl;
855 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
856 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
857 }
858 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
859 }
860 __error:
861 kfree(nctl);
862 kfree(gctl);
863 kfree(val);
864 return err;
865}
866
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100867static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
868 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869{
870 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100871 struct snd_ctl_elem_id id;
872 struct snd_ctl_elem_id __user *_id;
873 struct snd_emu10k1_fx8010_ctl *ctl;
874 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876 for (i = 0, _id = icode->gpr_del_controls;
877 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200878 if (copy_from_user(&id, _id, sizeof(id)))
879 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 down_write(&card->controls_rwsem);
881 ctl = snd_emu10k1_look_for_ctl(emu, &id);
882 if (ctl)
883 snd_ctl_remove(card, ctl->kcontrol);
884 up_write(&card->controls_rwsem);
885 }
886 return 0;
887}
888
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100889static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
890 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
892 unsigned int i = 0, j;
893 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100894 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100895 struct snd_emu10k1_fx8010_ctl *ctl;
896 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
898 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
899 if (! gctl)
900 return -ENOMEM;
901
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200902 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100904 if (icode->gpr_list_controls &&
905 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 memset(gctl, 0, sizeof(*gctl));
907 id = &ctl->kcontrol->id;
908 gctl->id.iface = id->iface;
909 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
910 gctl->id.index = id->index;
911 gctl->id.device = id->device;
912 gctl->id.subdevice = id->subdevice;
913 gctl->vcount = ctl->vcount;
914 gctl->count = ctl->count;
915 for (j = 0; j < 32; j++) {
916 gctl->gpr[j] = ctl->gpr[j];
917 gctl->value[j] = ctl->value[j];
918 }
919 gctl->min = ctl->min;
920 gctl->max = ctl->max;
921 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100922 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
923 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 kfree(gctl);
925 return -EFAULT;
926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 i++;
928 }
929 }
930 icode->gpr_list_control_total = total;
931 kfree(gctl);
932 return 0;
933}
934
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100935static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
936 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 int err = 0;
939
Ingo Molnar62932df2006-01-16 16:34:20 +0100940 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
942 goto __error;
943 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
944 /* stop FX processor - this may be dangerous, but it's better to miss
945 some samples than generate wrong ones - [jk] */
946 if (emu->audigy)
947 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
948 else
949 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
950 /* ok, do the main job */
951 if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 ||
952 (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 ||
953 (err = snd_emu10k1_tram_poke(emu, icode)) < 0 ||
954 (err = snd_emu10k1_code_poke(emu, icode)) < 0 ||
955 (err = snd_emu10k1_add_controls(emu, icode)) < 0)
956 goto __error;
957 /* start FX processor when the DSP code is updated */
958 if (emu->audigy)
959 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
960 else
961 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
962 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100963 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return err;
965}
966
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100967static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
968 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int err;
971
Ingo Molnar62932df2006-01-16 16:34:20 +0100972 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
974 /* ok, do the main job */
975 err = snd_emu10k1_gpr_peek(emu, icode);
976 if (err >= 0)
977 err = snd_emu10k1_tram_peek(emu, icode);
978 if (err >= 0)
979 err = snd_emu10k1_code_peek(emu, icode);
980 if (err >= 0)
981 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +0100982 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 return err;
984}
985
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100986static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
987 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
989 unsigned int i;
990 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100991 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
994 return -EINVAL;
995 if (ipcm->channels > 32)
996 return -EINVAL;
997 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +0100998 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 spin_lock_irq(&emu->reg_lock);
1000 if (pcm->opened) {
1001 err = -EBUSY;
1002 goto __error;
1003 }
1004 if (ipcm->channels == 0) { /* remove */
1005 pcm->valid = 0;
1006 } else {
1007 /* FIXME: we need to add universal code to the PCM transfer routine */
1008 if (ipcm->channels != 2) {
1009 err = -EINVAL;
1010 goto __error;
1011 }
1012 pcm->valid = 1;
1013 pcm->opened = 0;
1014 pcm->channels = ipcm->channels;
1015 pcm->tram_start = ipcm->tram_start;
1016 pcm->buffer_size = ipcm->buffer_size;
1017 pcm->gpr_size = ipcm->gpr_size;
1018 pcm->gpr_count = ipcm->gpr_count;
1019 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1020 pcm->gpr_ptr = ipcm->gpr_ptr;
1021 pcm->gpr_trigger = ipcm->gpr_trigger;
1022 pcm->gpr_running = ipcm->gpr_running;
1023 for (i = 0; i < pcm->channels; i++)
1024 pcm->etram[i] = ipcm->etram[i];
1025 }
1026 __error:
1027 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001028 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 return err;
1030}
1031
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001032static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1033 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
1035 unsigned int i;
1036 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001037 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1040 return -EINVAL;
1041 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001042 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 spin_lock_irq(&emu->reg_lock);
1044 ipcm->channels = pcm->channels;
1045 ipcm->tram_start = pcm->tram_start;
1046 ipcm->buffer_size = pcm->buffer_size;
1047 ipcm->gpr_size = pcm->gpr_size;
1048 ipcm->gpr_ptr = pcm->gpr_ptr;
1049 ipcm->gpr_count = pcm->gpr_count;
1050 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1051 ipcm->gpr_trigger = pcm->gpr_trigger;
1052 ipcm->gpr_running = pcm->gpr_running;
1053 for (i = 0; i < pcm->channels; i++)
1054 ipcm->etram[i] = pcm->etram[i];
1055 ipcm->res1 = ipcm->res2 = 0;
1056 ipcm->pad = 0;
1057 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001058 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return err;
1060}
1061
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001062#define SND_EMU10K1_GPR_CONTROLS 44
1063#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1065#define SND_EMU10K1_CAPTURE_CHANNELS 4
1066
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001067static void __devinit
1068snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1069 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
1071 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1072 strcpy(ctl->id.name, name);
1073 ctl->vcount = ctl->count = 1;
1074 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1075 ctl->min = 0;
1076 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001077 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1079}
1080
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001081static void __devinit
1082snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1083 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084{
1085 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1086 strcpy(ctl->id.name, name);
1087 ctl->vcount = ctl->count = 2;
1088 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1089 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1090 ctl->min = 0;
1091 ctl->max = 100;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001092 ctl->tlv = snd_emu10k1_db_scale1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1094}
1095
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001096static void __devinit
1097snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1098 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
1100 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1101 strcpy(ctl->id.name, name);
1102 ctl->vcount = ctl->count = 1;
1103 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1104 ctl->min = 0;
1105 ctl->max = 1;
1106 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1107}
1108
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001109static void __devinit
1110snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1111 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
1113 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1114 strcpy(ctl->id.name, name);
1115 ctl->vcount = ctl->count = 2;
1116 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1117 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1118 ctl->min = 0;
1119 ctl->max = 1;
1120 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1121}
1122
Pavel Hofman13d45702007-06-11 12:21:20 +02001123/*
1124 * Used for emu1010 - conversion from 32-bit capture inputs from HANA
1125 * to 2 x 16-bit registers in audigy - their values are read via DMA.
1126 * Conversion is performed by Audigy DSP instructions of FX8010.
1127 */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001128static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1129 struct snd_emu10k1_fx8010_code *icode,
1130 u32 *ptr, int tmp, int bit_shifter16,
1131 int reg_in, int reg_out)
1132{
1133 A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
1134 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
1135 A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
1136 A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
1137 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
1138 A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
1139 A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
1140 A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
1141 return 1;
1142}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144/*
1145 * initial DSP configuration for Audigy
1146 */
1147
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001148static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149{
1150 int err, i, z, gpr, nctl;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001151 int bit_shifter16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 const int playback = 10;
1153 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1154 const int stereo_mix = capture + 2;
1155 const int tmp = 0x88;
1156 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001157 struct snd_emu10k1_fx8010_code *icode = NULL;
1158 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 u32 *gpr_map;
1160 mm_segment_t seg;
1161
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001162 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001163 (icode->gpr_map = (u_int32_t __user *)
1164 kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
1165 GFP_KERNEL)) == NULL ||
1166 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1167 sizeof(*controls), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 err = -ENOMEM;
1169 goto __err;
1170 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001171 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172
1173 icode->tram_data_map = icode->gpr_map + 512;
1174 icode->tram_addr_map = icode->tram_data_map + 256;
1175 icode->code = icode->tram_addr_map + 256;
1176
1177 /* clear free GPRs */
1178 for (i = 0; i < 512; i++)
1179 set_bit(i, icode->gpr_valid);
1180
1181 /* clear TRAM data & address lines */
1182 for (i = 0; i < 256; i++)
1183 set_bit(i, icode->tram_valid);
1184
1185 strcpy(icode->name, "Audigy DSP code for ALSA");
1186 ptr = 0;
1187 nctl = 0;
1188 gpr = stereo_mix + 10;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001189 gpr_map[gpr++] = 0x00007fff;
1190 gpr_map[gpr++] = 0x00008000;
1191 gpr_map[gpr++] = 0x0000ffff;
1192 bit_shifter16 = gpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 /* stop FX processor */
1195 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1196
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001197#if 1
Pavel Hofman13d45702007-06-11 12:21:20 +02001198 /* PCM front Playback Volume (independent from stereo mix)
1199 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
1200 * where gpr contains attenuation from corresponding mixer control
1201 * (snd_emu10k1_init_stereo_control)
1202 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1204 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1205 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1206 gpr += 2;
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 /* PCM Surround Playback (independent from stereo mix) */
1209 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1210 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1211 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1212 gpr += 2;
1213
1214 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001215 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1217 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1218 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1219 gpr += 2;
1220 }
1221
1222 /* PCM Center Playback (independent from stereo mix) */
1223 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1224 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1225 gpr++;
1226
1227 /* PCM LFE Playback (independent from stereo mix) */
1228 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1229 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1230 gpr++;
1231
1232 /*
1233 * Stereo Mix
1234 */
1235 /* Wave (PCM) Playback Volume (will be renamed later) */
1236 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1237 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1238 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1239 gpr += 2;
1240
1241 /* Synth Playback */
1242 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1243 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1244 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1245 gpr += 2;
1246
1247 /* Wave (PCM) Capture */
1248 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1249 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1250 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1251 gpr += 2;
1252
1253 /* Synth Capture */
1254 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1255 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1256 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1257 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 /*
1260 * inputs
1261 */
1262#define A_ADD_VOLUME_IN(var,vol,input) \
1263A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1264
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001265 /* emu1212 DSP 0 and DSP 1 Capture */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001266 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001267 if (emu->card_capabilities->ca0108_chip) {
1268 /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
1269 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
1270 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
1271 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
1272 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
1273 } else {
1274 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1275 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1276 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001277 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1278 gpr += 2;
1279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 /* AC'97 Playback Volume - used only for mic (renamed later) */
1281 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1282 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1283 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1284 gpr += 2;
1285 /* AC'97 Capture Volume - used only for mic */
1286 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1287 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1288 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1289 gpr += 2;
1290
1291 /* mic capture buffer */
1292 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1293
1294 /* Audigy CD Playback Volume */
1295 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1296 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1297 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001298 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 gpr, 0);
1300 gpr += 2;
1301 /* Audigy CD Capture Volume */
1302 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1303 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1304 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001305 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 gpr, 0);
1307 gpr += 2;
1308
1309 /* Optical SPDIF Playback Volume */
1310 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1311 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001312 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 gpr += 2;
1314 /* Optical SPDIF Capture Volume */
1315 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1316 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001317 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 gpr += 2;
1319
1320 /* Line2 Playback Volume */
1321 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1322 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1323 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001324 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 gpr, 0);
1326 gpr += 2;
1327 /* Line2 Capture Volume */
1328 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1329 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1330 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001331 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 gpr, 0);
1333 gpr += 2;
1334
1335 /* Philips ADC Playback Volume */
1336 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1337 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1338 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1339 gpr += 2;
1340 /* Philips ADC Capture Volume */
1341 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1342 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1343 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1344 gpr += 2;
1345
1346 /* Aux2 Playback Volume */
1347 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1348 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1349 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001350 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 gpr, 0);
1352 gpr += 2;
1353 /* Aux2 Capture Volume */
1354 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1355 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1356 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001357 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 gpr, 0);
1359 gpr += 2;
1360
1361 /* Stereo Mix Front Playback Volume */
1362 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1363 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1364 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1365 gpr += 2;
1366
1367 /* Stereo Mix Surround Playback */
1368 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1369 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1370 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1371 gpr += 2;
1372
1373 /* Stereo Mix Center Playback */
1374 /* Center = sub = Left/2 + Right/2 */
1375 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1376 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1377 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1378 gpr++;
1379
1380 /* Stereo Mix LFE Playback */
1381 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1382 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1383 gpr++;
1384
Lee Revell2b637da2005-03-30 13:51:18 +02001385 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 /* Stereo Mix Side Playback */
1387 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1388 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1389 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1390 gpr += 2;
1391 }
1392
1393 /*
1394 * outputs
1395 */
1396#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1397#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1398 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1399
1400#define _A_SWITCH(icode, ptr, dst, src, sw) \
1401 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1402#define A_SWITCH(icode, ptr, dst, src, sw) \
1403 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1404#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1405 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1406#define A_SWITCH_NEG(icode, ptr, dst, src) \
1407 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1408
1409
1410 /*
1411 * Process tone control
1412 */
1413 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1414 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1415 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 */
1416 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 */
1417 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1418 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 +02001419 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 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 */
1421 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 */
1422 }
1423
1424
1425 ctl = &controls[nctl + 0];
1426 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1427 strcpy(ctl->id.name, "Tone Control - Bass");
1428 ctl->vcount = 2;
1429 ctl->count = 10;
1430 ctl->min = 0;
1431 ctl->max = 40;
1432 ctl->value[0] = ctl->value[1] = 20;
1433 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1434 ctl = &controls[nctl + 1];
1435 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1436 strcpy(ctl->id.name, "Tone Control - Treble");
1437 ctl->vcount = 2;
1438 ctl->count = 10;
1439 ctl->min = 0;
1440 ctl->max = 40;
1441 ctl->value[0] = ctl->value[1] = 20;
1442 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1443
1444#define BASS_GPR 0x8c
1445#define TREBLE_GPR 0x96
1446
1447 for (z = 0; z < 5; z++) {
1448 int j;
1449 for (j = 0; j < 2; j++) {
1450 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1451 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1452 }
1453 }
1454 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1455 int j, k, l, d;
1456 for (j = 0; j < 2; j++) { /* left/right */
1457 k = 0xb0 + (z * 8) + (j * 4);
1458 l = 0xe0 + (z * 8) + (j * 4);
1459 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1460
1461 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1462 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1463 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1464 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1465 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1466 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1467
1468 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1469 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1470 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1471 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1472 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1473 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1474
1475 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1476
1477 if (z == 2) /* center */
1478 break;
1479 }
1480 }
1481 nctl += 2;
1482
1483#undef BASS_GPR
1484#undef TREBLE_GPR
1485
1486 for (z = 0; z < 8; z++) {
1487 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1488 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1489 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1490 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1491 }
1492 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1493 gpr += 2;
1494
1495 /* Master volume (will be renamed later) */
1496 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));
1497 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));
1498 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));
1499 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));
1500 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));
1501 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));
1502 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));
1503 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));
1504 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1505 gpr += 2;
1506
1507 /* analog speakers */
1508 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1509 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1510 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1511 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001512 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1514
1515 /* headphone */
1516 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1517
1518 /* digital outputs */
1519 /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001520 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001521 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
1522 snd_printk("EMU outputs on\n");
1523 for (z = 0; z < 8; z++) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001524 if (emu->card_capabilities->ca0108_chip) {
1525 A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1526 } else {
1527 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1528 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001529 }
1530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 /* IEC958 Optical Raw Playback Switch */
1533 gpr_map[gpr++] = 0;
1534 gpr_map[gpr++] = 0x1008;
1535 gpr_map[gpr++] = 0xffff0000;
1536 for (z = 0; z < 2; z++) {
1537 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1538 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1539 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1540 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1541 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1542 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1543 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1544 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1545 /* 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 +02001546 snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1548 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1549 } else {
1550 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1551 }
1552 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001553 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 -07001554 gpr += 2;
1555
1556 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1557 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1558 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1559
1560 /* ADC buffer */
1561#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1562 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1563#else
1564 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1565 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1566#endif
1567
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001568 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001569 if (emu->card_capabilities->ca0108_chip) {
1570 snd_printk("EMU2 inputs on\n");
1571 for (z = 0; z < 0x10; z++) {
1572 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
1573 bit_shifter16,
1574 A3_EMU32IN(z),
1575 A_FXBUS2(z*2) );
1576 }
1577 } else {
1578 snd_printk("EMU inputs on\n");
1579 /* Capture 16 (originally 8) channels of S32_LE sound */
1580
1581 /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
1582 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1583 /* A_P16VIN(0) is delayed by one sample,
1584 * so all other A_P16VIN channels will need to also be delayed
1585 */
1586 /* Left ADC in. 1 of 2 */
1587 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1588 /* Right ADC in 1 of 2 */
1589 gpr_map[gpr++] = 0x00000000;
1590 /* Delaying by one sample: instead of copying the input
1591 * value A_P16VIN to output A_FXBUS2 as in the first channel,
1592 * we use an auxiliary register, delaying the value by one
1593 * sample
1594 */
1595 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1596 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1597 gpr_map[gpr++] = 0x00000000;
1598 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1599 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), 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(6) );
1602 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1603 /* For 96kHz mode */
1604 /* Left ADC in. 2 of 2 */
1605 gpr_map[gpr++] = 0x00000000;
1606 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1607 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1608 /* Right ADC in 2 of 2 */
1609 gpr_map[gpr++] = 0x00000000;
1610 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1611 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
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(0xc) );
1614 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), 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(0xe) );
1617 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1618 /* Pavel Hofman - we still have voices, A_FXBUS2s, and
1619 * A_P16VINs available -
1620 * let's add 8 more capture channels - total of 16
1621 */
1622 gpr_map[gpr++] = 0x00000000;
1623 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1624 bit_shifter16,
1625 A_GPR(gpr - 1),
1626 A_FXBUS2(0x10));
1627 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
1628 A_C_00000000, A_C_00000000);
1629 gpr_map[gpr++] = 0x00000000;
1630 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1631 bit_shifter16,
1632 A_GPR(gpr - 1),
1633 A_FXBUS2(0x12));
1634 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
1635 A_C_00000000, A_C_00000000);
1636 gpr_map[gpr++] = 0x00000000;
1637 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1638 bit_shifter16,
1639 A_GPR(gpr - 1),
1640 A_FXBUS2(0x14));
1641 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
1642 A_C_00000000, A_C_00000000);
1643 gpr_map[gpr++] = 0x00000000;
1644 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1645 bit_shifter16,
1646 A_GPR(gpr - 1),
1647 A_FXBUS2(0x16));
1648 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
1649 A_C_00000000, A_C_00000000);
1650 gpr_map[gpr++] = 0x00000000;
1651 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1652 bit_shifter16,
1653 A_GPR(gpr - 1),
1654 A_FXBUS2(0x18));
1655 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
1656 A_C_00000000, A_C_00000000);
1657 gpr_map[gpr++] = 0x00000000;
1658 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1659 bit_shifter16,
1660 A_GPR(gpr - 1),
1661 A_FXBUS2(0x1a));
1662 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
1663 A_C_00000000, A_C_00000000);
1664 gpr_map[gpr++] = 0x00000000;
1665 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1666 bit_shifter16,
1667 A_GPR(gpr - 1),
1668 A_FXBUS2(0x1c));
1669 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
1670 A_C_00000000, A_C_00000000);
1671 gpr_map[gpr++] = 0x00000000;
1672 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1673 bit_shifter16,
1674 A_GPR(gpr - 1),
1675 A_FXBUS2(0x1e));
1676 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
1677 A_C_00000000, A_C_00000000);
1678 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001679
1680#if 0
1681 for (z = 4; z < 8; z++) {
1682 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1683 }
1684 for (z = 0xc; z < 0x10; z++) {
1685 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1686 }
1687#endif
1688 } else {
1689 /* EFX capture - capture the 16 EXTINs */
1690 /* Capture 16 channels of S16_LE sound */
1691 for (z = 0; z < 16; z++) {
1692 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 }
1695
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001696#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 /*
1698 * ok, set up done..
1699 */
1700
1701 if (gpr > tmp) {
1702 snd_BUG();
1703 err = -EIO;
1704 goto __err;
1705 }
1706 /* clear remaining instruction memory */
1707 while (ptr < 0x400)
1708 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1709
1710 seg = snd_enter_user();
1711 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001712 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001713 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001715 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 snd_leave_user(seg);
1717
1718 __err:
1719 kfree(controls);
1720 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02001721 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 kfree(icode);
1723 }
1724 return err;
1725}
1726
1727
1728/*
1729 * initial DSP configuration for Emu10k1
1730 */
1731
1732/* when volume = max, then copy only to avoid volume modification */
1733/* with iMAC0 (negative values) */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001734static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735{
1736 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1737 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1738 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1739 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1740}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001741static 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 -07001742{
1743 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1744 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1745 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1746 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1747 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1748}
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001749static 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 -07001750{
1751 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1752 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1753 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1754 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1755 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1756}
1757
1758#define VOLUME(icode, ptr, dst, src, vol) \
1759 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1760#define VOLUME_IN(icode, ptr, dst, src, vol) \
1761 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1762#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1763 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1764#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1765 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1766#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1767 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1768#define _SWITCH(icode, ptr, dst, src, sw) \
1769 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1770#define SWITCH(icode, ptr, dst, src, sw) \
1771 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1772#define SWITCH_IN(icode, ptr, dst, src, sw) \
1773 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1774#define _SWITCH_NEG(icode, ptr, dst, src) \
1775 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1776#define SWITCH_NEG(icode, ptr, dst, src) \
1777 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1778
1779
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001780static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
1782 int err, i, z, gpr, tmp, playback, capture;
1783 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001784 struct snd_emu10k1_fx8010_code *icode;
1785 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1786 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 u32 *gpr_map;
1788 mm_segment_t seg;
1789
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001790 if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return -ENOMEM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001792 if ((icode->gpr_map = (u_int32_t __user *)
1793 kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
1794 GFP_KERNEL)) == NULL ||
1795 (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1796 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1797 GFP_KERNEL)) == NULL ||
Takashi Iwaie560d8d2005-09-09 14:21:46 +02001798 (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 err = -ENOMEM;
1800 goto __err;
1801 }
Clemens Ladisch4d233592005-09-05 10:35:20 +02001802 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 icode->tram_data_map = icode->gpr_map + 256;
1805 icode->tram_addr_map = icode->tram_data_map + 160;
1806 icode->code = icode->tram_addr_map + 160;
1807
1808 /* clear free GPRs */
1809 for (i = 0; i < 256; i++)
1810 set_bit(i, icode->gpr_valid);
1811
1812 /* clear TRAM data & address lines */
1813 for (i = 0; i < 160; i++)
1814 set_bit(i, icode->tram_valid);
1815
1816 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1817 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001818 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 playback = SND_EMU10K1_INPUTS;
1820 /* we have 6 playback channels and tone control doubles */
1821 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1822 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1823 tmp = 0x88; /* we need 4 temporary GPR */
1824 /* from 0x8c to 0xff is the area for tone control */
1825
1826 /* stop FX processor */
1827 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1828
1829 /*
1830 * Process FX Buses
1831 */
1832 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1833 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1834 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1835 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1836 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1837 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1838 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1839 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1840 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1841 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001842 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1843 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 /* Raw S/PDIF PCM */
1846 ipcm->substream = 0;
1847 ipcm->channels = 2;
1848 ipcm->tram_start = 0;
1849 ipcm->buffer_size = (64 * 1024) / 2;
1850 ipcm->gpr_size = gpr++;
1851 ipcm->gpr_ptr = gpr++;
1852 ipcm->gpr_count = gpr++;
1853 ipcm->gpr_tmpcount = gpr++;
1854 ipcm->gpr_trigger = gpr++;
1855 ipcm->gpr_running = gpr++;
1856 ipcm->etram[0] = 0;
1857 ipcm->etram[1] = 1;
1858
1859 gpr_map[gpr + 0] = 0xfffff000;
1860 gpr_map[gpr + 1] = 0xffff0000;
1861 gpr_map[gpr + 2] = 0x70000000;
1862 gpr_map[gpr + 3] = 0x00000007;
1863 gpr_map[gpr + 4] = 0x001f << 11;
1864 gpr_map[gpr + 5] = 0x001c << 11;
1865 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1866 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1867 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1868 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1869 gpr_map[gpr + 10] = 1<<11;
1870 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1871 gpr_map[gpr + 12] = 0;
1872
1873 /* if the trigger flag is not set, skip */
1874 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1875 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1876 /* if the running flag is set, we're running */
1877 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1878 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1879 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1880 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1881 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1882 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1883 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1884
1885 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1886 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1887 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1888 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1889
1890 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1891 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1892 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1893 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1894 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1895
1896 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1897 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1898 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1899 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1900 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1901
1902 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1903 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1904 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1905 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1906 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1907
1908 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1909 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1910 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1911 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1912 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1913
1914 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1915 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1916
1917 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1918 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1919
1920 /* 24: */
1921 gpr += 13;
1922
1923 /* Wave Playback Volume */
1924 for (z = 0; z < 2; z++)
1925 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1926 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1927 gpr += 2;
1928
1929 /* Wave Surround Playback Volume */
1930 for (z = 0; z < 2; z++)
1931 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1932 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1933 gpr += 2;
1934
1935 /* Wave Center/LFE Playback Volume */
1936 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1937 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1938 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1939 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1940 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1941 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1942
1943 /* Wave Capture Volume + Switch */
1944 for (z = 0; z < 2; z++) {
1945 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1946 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
1947 }
1948 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
1949 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
1950 gpr += 4;
1951
1952 /* Synth Playback Volume */
1953 for (z = 0; z < 2; z++)
1954 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
1955 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
1956 gpr += 2;
1957
1958 /* Synth Capture Volume + Switch */
1959 for (z = 0; z < 2; z++) {
1960 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
1961 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1962 }
1963 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
1964 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
1965 gpr += 4;
1966
1967 /* Surround Digital Playback Volume (renamed later without Digital) */
1968 for (z = 0; z < 2; z++)
1969 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
1970 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
1971 gpr += 2;
1972
1973 /* Surround Capture Volume + Switch */
1974 for (z = 0; z < 2; z++) {
1975 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
1976 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
1977 }
1978 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
1979 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
1980 gpr += 4;
1981
1982 /* Center Playback Volume (renamed later without Digital) */
1983 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
1984 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
1985
1986 /* LFE Playback Volume + Switch (renamed later without Digital) */
1987 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
1988 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
1989
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001990 /* Front Playback Volume */
1991 for (z = 0; z < 2; z++)
1992 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
1993 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
1994 gpr += 2;
1995
1996 /* Front Capture Volume + Switch */
1997 for (z = 0; z < 2; z++) {
1998 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
1999 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2000 }
2001 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2002 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2003 gpr += 3;
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 /*
2006 * Process inputs
2007 */
2008
2009 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
2010 /* AC'97 Playback Volume */
2011 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
2012 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
2013 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
2014 /* AC'97 Capture Volume */
2015 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
2016 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
2017 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
2018 }
2019
2020 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
2021 /* IEC958 TTL Playback Volume */
2022 for (z = 0; z < 2; z++)
2023 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002024 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 gpr += 2;
2026
2027 /* IEC958 TTL Capture Volume + Switch */
2028 for (z = 0; z < 2; z++) {
2029 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
2030 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2031 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002032 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
2033 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 -07002034 gpr += 4;
2035 }
2036
2037 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
2038 /* Zoom Video Playback Volume */
2039 for (z = 0; z < 2; z++)
2040 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
2041 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
2042 gpr += 2;
2043
2044 /* Zoom Video Capture Volume + Switch */
2045 for (z = 0; z < 2; z++) {
2046 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
2047 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2048 }
2049 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
2050 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
2051 gpr += 4;
2052 }
2053
2054 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
2055 /* IEC958 Optical Playback Volume */
2056 for (z = 0; z < 2; z++)
2057 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002058 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 gpr += 2;
2060
2061 /* IEC958 Optical Capture Volume */
2062 for (z = 0; z < 2; z++) {
2063 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
2064 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2065 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002066 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
2067 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 -07002068 gpr += 4;
2069 }
2070
2071 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
2072 /* Line LiveDrive Playback Volume */
2073 for (z = 0; z < 2; z++)
2074 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
2075 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
2076 gpr += 2;
2077
2078 /* Line LiveDrive Capture Volume + Switch */
2079 for (z = 0; z < 2; z++) {
2080 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
2081 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2082 }
2083 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
2084 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
2085 gpr += 4;
2086 }
2087
2088 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
2089 /* IEC958 Coax Playback Volume */
2090 for (z = 0; z < 2; z++)
2091 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002092 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 gpr += 2;
2094
2095 /* IEC958 Coax Capture Volume + Switch */
2096 for (z = 0; z < 2; z++) {
2097 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2098 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2099 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002100 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2101 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 -07002102 gpr += 4;
2103 }
2104
2105 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2106 /* Line LiveDrive Playback Volume */
2107 for (z = 0; z < 2; z++)
2108 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2109 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2110 controls[i-1].id.index = 1;
2111 gpr += 2;
2112
2113 /* Line LiveDrive Capture Volume */
2114 for (z = 0; z < 2; z++) {
2115 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2116 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2117 }
2118 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2119 controls[i-1].id.index = 1;
2120 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2121 controls[i-1].id.index = 1;
2122 gpr += 4;
2123 }
2124
2125 /*
2126 * Process tone control
2127 */
2128 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2129 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2130 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2131 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2132 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2133 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2134
2135 ctl = &controls[i + 0];
2136 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2137 strcpy(ctl->id.name, "Tone Control - Bass");
2138 ctl->vcount = 2;
2139 ctl->count = 10;
2140 ctl->min = 0;
2141 ctl->max = 40;
2142 ctl->value[0] = ctl->value[1] = 20;
2143 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2144 ctl = &controls[i + 1];
2145 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2146 strcpy(ctl->id.name, "Tone Control - Treble");
2147 ctl->vcount = 2;
2148 ctl->count = 10;
2149 ctl->min = 0;
2150 ctl->max = 40;
2151 ctl->value[0] = ctl->value[1] = 20;
2152 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2153
2154#define BASS_GPR 0x8c
2155#define TREBLE_GPR 0x96
2156
2157 for (z = 0; z < 5; z++) {
2158 int j;
2159 for (j = 0; j < 2; j++) {
2160 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2161 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2162 }
2163 }
2164 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2165 int j, k, l, d;
2166 for (j = 0; j < 2; j++) { /* left/right */
2167 k = 0xa0 + (z * 8) + (j * 4);
2168 l = 0xd0 + (z * 8) + (j * 4);
2169 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2170
2171 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2172 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2173 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2174 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2175 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2176 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2177
2178 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2179 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2180 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2181 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2182 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2183 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2184
2185 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2186
2187 if (z == 2) /* center */
2188 break;
2189 }
2190 }
2191 i += 2;
2192
2193#undef BASS_GPR
2194#undef TREBLE_GPR
2195
2196 for (z = 0; z < 6; z++) {
2197 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2198 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2199 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2200 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2201 }
2202 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2203 gpr += 2;
2204
2205 /*
2206 * Process outputs
2207 */
2208 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2209 /* AC'97 Playback Volume */
2210
2211 for (z = 0; z < 2; z++)
2212 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2213 }
2214
2215 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2216 /* IEC958 Optical Raw Playback Switch */
2217
2218 for (z = 0; z < 2; z++) {
2219 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2220 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2221 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2222 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2223#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2224 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2225#endif
2226 }
2227
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002228 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 -07002229 gpr += 2;
2230 }
2231
2232 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2233 /* Headphone Playback Volume */
2234
2235 for (z = 0; z < 2; z++) {
2236 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2237 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2238 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2239 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2240 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2241 }
2242
2243 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2244 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2245 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2246 controls[i-1].id.index = 1;
2247 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2248 controls[i-1].id.index = 1;
2249
2250 gpr += 4;
2251 }
2252
2253 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2254 for (z = 0; z < 2; z++)
2255 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2256
2257 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2258 for (z = 0; z < 2; z++)
2259 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2260
2261 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2262#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2263 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2264 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2265#else
2266 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2267 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2268#endif
2269 }
2270
2271 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2272#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2273 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2274 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2275#else
2276 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2277 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2278#endif
2279 }
2280
2281#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2282 for (z = 0; z < 2; z++)
2283 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2284#endif
2285
2286 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2287 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2288
2289 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002290 if (emu->card_capabilities->sblive51) {
2291 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2292 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2293 *
2294 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2295 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2296 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2297 * channel. Multitrack recorders will still see the center/lfe output signal
2298 * on the second and third channels.
2299 */
2300 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2301 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2302 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2303 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2304 for (z = 4; z < 14; z++)
2305 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2306 } else {
2307 for (z = 0; z < 16; z++)
2308 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 }
Lee Revell2b637da2005-03-30 13:51:18 +02002310
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 if (gpr > tmp) {
2313 snd_BUG();
2314 err = -EIO;
2315 goto __err;
2316 }
2317 if (i > SND_EMU10K1_GPR_CONTROLS) {
2318 snd_BUG();
2319 err = -EIO;
2320 goto __err;
2321 }
2322
2323 /* clear remaining instruction memory */
2324 while (ptr < 0x200)
2325 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2326
2327 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2328 goto __err;
2329 seg = snd_enter_user();
2330 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002331 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002332 emu->support_tlv = 1; /* support TLV */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 err = snd_emu10k1_icode_poke(emu, icode);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002334 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 snd_leave_user(seg);
2336 if (err >= 0)
2337 err = snd_emu10k1_ipcm_poke(emu, ipcm);
2338 __err:
2339 kfree(ipcm);
2340 kfree(controls);
2341 if (icode != NULL) {
Clemens Ladisch4d233592005-09-05 10:35:20 +02002342 kfree((void __force *)icode->gpr_map);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 kfree(icode);
2344 }
2345 return err;
2346}
2347
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002348int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349{
Takashi Iwai09668b42005-11-17 16:14:10 +01002350 spin_lock_init(&emu->fx8010.irq_lock);
2351 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 if (emu->audigy)
2353 return _snd_emu10k1_audigy_init_efx(emu);
2354 else
2355 return _snd_emu10k1_init_efx(emu);
2356}
2357
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002358void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359{
2360 /* stop processor */
2361 if (emu->audigy)
2362 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2363 else
2364 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2365}
2366
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002367#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002368int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002370 if (output < 0 || output >= 6)
2371 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2373 return 0;
2374}
2375
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002376int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002378 if (output < 0 || output >= 6)
2379 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2381 return 0;
2382}
2383#endif
2384
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002385int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386{
2387 u8 size_reg = 0;
2388
2389 /* size is in samples */
2390 if (size != 0) {
2391 size = (size - 1) >> 13;
2392
2393 while (size) {
2394 size >>= 1;
2395 size_reg++;
2396 }
2397 size = 0x2000 << size_reg;
2398 }
2399 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2400 return 0;
2401 spin_lock_irq(&emu->emu_lock);
2402 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2403 spin_unlock_irq(&emu->emu_lock);
2404 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2405 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2406 if (emu->fx8010.etram_pages.area != NULL) {
2407 snd_dma_free_pages(&emu->fx8010.etram_pages);
2408 emu->fx8010.etram_pages.area = NULL;
2409 emu->fx8010.etram_pages.bytes = 0;
2410 }
2411
2412 if (size > 0) {
2413 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2414 size * 2, &emu->fx8010.etram_pages) < 0)
2415 return -ENOMEM;
2416 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2417 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2418 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2419 spin_lock_irq(&emu->emu_lock);
2420 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002421 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 }
2423
2424 return 0;
2425}
2426
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002427static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428{
2429 return 0;
2430}
2431
2432static void copy_string(char *dst, char *src, char *null, int idx)
2433{
2434 if (src == NULL)
2435 sprintf(dst, "%s %02X", null, idx);
2436 else
2437 strcpy(dst, src);
2438}
2439
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002440static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002441 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442{
2443 char **fxbus, **extin, **extout;
2444 unsigned short fxbus_mask, extin_mask, extout_mask;
2445 int res;
2446
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 info->internal_tram_size = emu->fx8010.itram_size;
2448 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2449 fxbus = fxbuses;
2450 extin = emu->audigy ? audigy_ins : creative_ins;
2451 extout = emu->audigy ? audigy_outs : creative_outs;
2452 fxbus_mask = emu->fx8010.fxbus_mask;
2453 extin_mask = emu->fx8010.extin_mask;
2454 extout_mask = emu->fx8010.extout_mask;
2455 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2456 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2457 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2458 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2459 }
2460 for (res = 16; res < 32; res++, extout++)
2461 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2462 info->gpr_controls = emu->fx8010.gpr_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463}
2464
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002465static 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 -07002466{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002467 struct snd_emu10k1 *emu = hw->private_data;
2468 struct snd_emu10k1_fx8010_info *info;
2469 struct snd_emu10k1_fx8010_code *icode;
2470 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 unsigned int addr;
2472 void __user *argp = (void __user *)arg;
2473 int res;
2474
2475 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002476 case SNDRV_EMU10K1_IOCTL_PVERSION:
2477 emu->support_tlv = 1;
2478 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 case SNDRV_EMU10K1_IOCTL_INFO:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002480 info = kmalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 if (!info)
2482 return -ENOMEM;
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002483 snd_emu10k1_fx8010_info(emu, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 if (copy_to_user(argp, info, sizeof(*info))) {
2485 kfree(info);
2486 return -EFAULT;
2487 }
2488 kfree(info);
2489 return 0;
2490 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2491 if (!capable(CAP_SYS_ADMIN))
2492 return -EPERM;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002493 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 if (icode == NULL)
2495 return -ENOMEM;
2496 if (copy_from_user(icode, argp, sizeof(*icode))) {
2497 kfree(icode);
2498 return -EFAULT;
2499 }
2500 res = snd_emu10k1_icode_poke(emu, icode);
2501 kfree(icode);
2502 return res;
2503 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002504 icode = kmalloc(sizeof(*icode), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 if (icode == NULL)
2506 return -ENOMEM;
2507 if (copy_from_user(icode, argp, sizeof(*icode))) {
2508 kfree(icode);
2509 return -EFAULT;
2510 }
2511 res = snd_emu10k1_icode_peek(emu, icode);
2512 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2513 kfree(icode);
2514 return -EFAULT;
2515 }
2516 kfree(icode);
2517 return res;
2518 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002519 ipcm = kmalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 if (ipcm == NULL)
2521 return -ENOMEM;
2522 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2523 kfree(ipcm);
2524 return -EFAULT;
2525 }
2526 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2527 kfree(ipcm);
2528 return res;
2529 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Takashi Iwaie560d8d2005-09-09 14:21:46 +02002530 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 if (ipcm == NULL)
2532 return -ENOMEM;
2533 if (copy_from_user(ipcm, argp, sizeof(*ipcm))) {
2534 kfree(ipcm);
2535 return -EFAULT;
2536 }
2537 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2538 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2539 kfree(ipcm);
2540 return -EFAULT;
2541 }
2542 kfree(ipcm);
2543 return res;
2544 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2545 if (!capable(CAP_SYS_ADMIN))
2546 return -EPERM;
2547 if (get_user(addr, (unsigned int __user *)argp))
2548 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002549 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002551 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 return res;
2553 case SNDRV_EMU10K1_IOCTL_STOP:
2554 if (!capable(CAP_SYS_ADMIN))
2555 return -EPERM;
2556 if (emu->audigy)
2557 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2558 else
2559 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2560 return 0;
2561 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2562 if (!capable(CAP_SYS_ADMIN))
2563 return -EPERM;
2564 if (emu->audigy)
2565 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2566 else
2567 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2568 return 0;
2569 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2570 if (!capable(CAP_SYS_ADMIN))
2571 return -EPERM;
2572 if (emu->audigy)
2573 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2574 else
2575 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2576 udelay(10);
2577 if (emu->audigy)
2578 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2579 else
2580 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2581 return 0;
2582 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2583 if (!capable(CAP_SYS_ADMIN))
2584 return -EPERM;
2585 if (get_user(addr, (unsigned int __user *)argp))
2586 return -EFAULT;
2587 if (addr > 0x1ff)
2588 return -EINVAL;
2589 if (emu->audigy)
2590 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2591 else
2592 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2593 udelay(10);
2594 if (emu->audigy)
2595 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2596 else
2597 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2598 return 0;
2599 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2600 if (emu->audigy)
2601 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2602 else
2603 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2604 if (put_user(addr, (unsigned int __user *)argp))
2605 return -EFAULT;
2606 return 0;
2607 }
2608 return -ENOTTY;
2609}
2610
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002611static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612{
2613 return 0;
2614}
2615
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002616int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002618 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 int err;
2620
2621 if (rhwdep)
2622 *rhwdep = NULL;
2623 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2624 return err;
2625 strcpy(hw->name, "EMU10K1 (FX8010)");
2626 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2627 hw->ops.open = snd_emu10k1_fx8010_open;
2628 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2629 hw->ops.release = snd_emu10k1_fx8010_release;
2630 hw->private_data = emu;
2631 if (rhwdep)
2632 *rhwdep = hw;
2633 return 0;
2634}
Takashi Iwai09668b42005-11-17 16:14:10 +01002635
2636#ifdef CONFIG_PM
2637int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
2638{
2639 int len;
2640
2641 len = emu->audigy ? 0x200 : 0x100;
2642 emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
2643 if (! emu->saved_gpr)
2644 return -ENOMEM;
2645 len = emu->audigy ? 0x100 : 0xa0;
2646 emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
2647 emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
2648 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2649 return -ENOMEM;
2650 len = emu->audigy ? 2 * 1024 : 2 * 512;
2651 emu->saved_icode = vmalloc(len * 4);
2652 if (! emu->saved_icode)
2653 return -ENOMEM;
2654 return 0;
2655}
2656
2657void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2658{
2659 kfree(emu->saved_gpr);
2660 kfree(emu->tram_val_saved);
2661 kfree(emu->tram_addr_saved);
2662 vfree(emu->saved_icode);
2663}
2664
2665/*
2666 * save/restore GPR, TRAM and codes
2667 */
2668void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2669{
2670 int i, len;
2671
2672 len = emu->audigy ? 0x200 : 0x100;
2673 for (i = 0; i < len; i++)
2674 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2675
2676 len = emu->audigy ? 0x100 : 0xa0;
2677 for (i = 0; i < len; i++) {
2678 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2679 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2680 if (emu->audigy) {
2681 emu->tram_addr_saved[i] >>= 12;
2682 emu->tram_addr_saved[i] |=
2683 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2684 }
2685 }
2686
2687 len = emu->audigy ? 2 * 1024 : 2 * 512;
2688 for (i = 0; i < len; i++)
2689 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2690}
2691
2692void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2693{
2694 int i, len;
2695
2696 /* set up TRAM */
2697 if (emu->fx8010.etram_pages.bytes > 0) {
2698 unsigned size, size_reg = 0;
2699 size = emu->fx8010.etram_pages.bytes / 2;
2700 size = (size - 1) >> 13;
2701 while (size) {
2702 size >>= 1;
2703 size_reg++;
2704 }
2705 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2706 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2707 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2708 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2709 }
2710
2711 if (emu->audigy)
2712 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2713 else
2714 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2715
2716 len = emu->audigy ? 0x200 : 0x100;
2717 for (i = 0; i < len; i++)
2718 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2719
2720 len = emu->audigy ? 0x100 : 0xa0;
2721 for (i = 0; i < len; i++) {
2722 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2723 emu->tram_val_saved[i]);
2724 if (! emu->audigy)
2725 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2726 emu->tram_addr_saved[i]);
2727 else {
2728 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2729 emu->tram_addr_saved[i] << 12);
2730 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2731 emu->tram_addr_saved[i] >> 20);
2732 }
2733 }
2734
2735 len = emu->audigy ? 2 * 1024 : 2 * 512;
2736 for (i = 0; i < len; i++)
2737 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2738
2739 /* start FX processor when the DSP code is updated */
2740 if (emu->audigy)
2741 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2742 else
2743 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2744}
2745#endif