blob: 1f25e6d029d82db67c195acf228c33e9ab5208fb [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>
Clemens Ladisch4daf7a02010-05-25 09:04:49 +020038#include <linux/moduleparam.h>
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -060039#include <linux/nospec.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010040
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <sound/core.h>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010042#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <sound/emu10k1.h>
44
45#if 0 /* for testing purposes - digital out -> capture */
46#define EMU10K1_CAPTURE_DIGITAL_OUT
47#endif
48#if 0 /* for testing purposes - set S/PDIF to AC3 output */
49#define EMU10K1_SET_AC3_IEC958
50#endif
51#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
52#define EMU10K1_CENTER_LFE_FROM_FRONT
53#endif
54
Clemens Ladisch4daf7a02010-05-25 09:04:49 +020055static bool high_res_gpr_volume;
56module_param(high_res_gpr_volume, bool, 0444);
57MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/*
60 * Tables
61 */
62
63static char *fxbuses[16] = {
64 /* 0x00 */ "PCM Left",
65 /* 0x01 */ "PCM Right",
66 /* 0x02 */ "PCM Surround Left",
67 /* 0x03 */ "PCM Surround Right",
68 /* 0x04 */ "MIDI Left",
69 /* 0x05 */ "MIDI Right",
70 /* 0x06 */ "Center",
71 /* 0x07 */ "LFE",
72 /* 0x08 */ NULL,
73 /* 0x09 */ NULL,
74 /* 0x0a */ NULL,
75 /* 0x0b */ NULL,
76 /* 0x0c */ "MIDI Reverb",
77 /* 0x0d */ "MIDI Chorus",
78 /* 0x0e */ NULL,
79 /* 0x0f */ NULL
80};
81
82static char *creative_ins[16] = {
83 /* 0x00 */ "AC97 Left",
84 /* 0x01 */ "AC97 Right",
85 /* 0x02 */ "TTL IEC958 Left",
86 /* 0x03 */ "TTL IEC958 Right",
87 /* 0x04 */ "Zoom Video Left",
88 /* 0x05 */ "Zoom Video Right",
89 /* 0x06 */ "Optical IEC958 Left",
90 /* 0x07 */ "Optical IEC958 Right",
91 /* 0x08 */ "Line/Mic 1 Left",
92 /* 0x09 */ "Line/Mic 1 Right",
93 /* 0x0a */ "Coaxial IEC958 Left",
94 /* 0x0b */ "Coaxial IEC958 Right",
95 /* 0x0c */ "Line/Mic 2 Left",
96 /* 0x0d */ "Line/Mic 2 Right",
97 /* 0x0e */ NULL,
98 /* 0x0f */ NULL
99};
100
101static char *audigy_ins[16] = {
102 /* 0x00 */ "AC97 Left",
103 /* 0x01 */ "AC97 Right",
104 /* 0x02 */ "Audigy CD Left",
105 /* 0x03 */ "Audigy CD Right",
106 /* 0x04 */ "Optical IEC958 Left",
107 /* 0x05 */ "Optical IEC958 Right",
108 /* 0x06 */ NULL,
109 /* 0x07 */ NULL,
110 /* 0x08 */ "Line/Mic 2 Left",
111 /* 0x09 */ "Line/Mic 2 Right",
112 /* 0x0a */ "SPDIF Left",
113 /* 0x0b */ "SPDIF Right",
114 /* 0x0c */ "Aux2 Left",
115 /* 0x0d */ "Aux2 Right",
116 /* 0x0e */ NULL,
117 /* 0x0f */ NULL
118};
119
120static char *creative_outs[32] = {
121 /* 0x00 */ "AC97 Left",
122 /* 0x01 */ "AC97 Right",
123 /* 0x02 */ "Optical IEC958 Left",
124 /* 0x03 */ "Optical IEC958 Right",
125 /* 0x04 */ "Center",
126 /* 0x05 */ "LFE",
127 /* 0x06 */ "Headphone Left",
128 /* 0x07 */ "Headphone Right",
129 /* 0x08 */ "Surround Left",
130 /* 0x09 */ "Surround Right",
131 /* 0x0a */ "PCM Capture Left",
132 /* 0x0b */ "PCM Capture Right",
133 /* 0x0c */ "MIC Capture",
134 /* 0x0d */ "AC97 Surround Left",
135 /* 0x0e */ "AC97 Surround Right",
136 /* 0x0f */ NULL,
137 /* 0x10 */ NULL,
138 /* 0x11 */ "Analog Center",
139 /* 0x12 */ "Analog LFE",
140 /* 0x13 */ NULL,
141 /* 0x14 */ NULL,
142 /* 0x15 */ NULL,
143 /* 0x16 */ NULL,
144 /* 0x17 */ NULL,
145 /* 0x18 */ NULL,
146 /* 0x19 */ NULL,
147 /* 0x1a */ NULL,
148 /* 0x1b */ NULL,
149 /* 0x1c */ NULL,
150 /* 0x1d */ NULL,
151 /* 0x1e */ NULL,
152 /* 0x1f */ NULL,
153};
154
155static char *audigy_outs[32] = {
156 /* 0x00 */ "Digital Front Left",
157 /* 0x01 */ "Digital Front Right",
158 /* 0x02 */ "Digital Center",
159 /* 0x03 */ "Digital LEF",
160 /* 0x04 */ "Headphone Left",
161 /* 0x05 */ "Headphone Right",
162 /* 0x06 */ "Digital Rear Left",
163 /* 0x07 */ "Digital Rear Right",
164 /* 0x08 */ "Front Left",
165 /* 0x09 */ "Front Right",
166 /* 0x0a */ "Center",
167 /* 0x0b */ "LFE",
168 /* 0x0c */ NULL,
169 /* 0x0d */ NULL,
170 /* 0x0e */ "Rear Left",
171 /* 0x0f */ "Rear Right",
172 /* 0x10 */ "AC97 Front Left",
173 /* 0x11 */ "AC97 Front Right",
Colin Ian Kingbf8b47f2018-05-17 09:04:20 +0100174 /* 0x12 */ "ADC Capture Left",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 /* 0x13 */ "ADC Capture Right",
176 /* 0x14 */ NULL,
177 /* 0x15 */ NULL,
178 /* 0x16 */ NULL,
179 /* 0x17 */ NULL,
180 /* 0x18 */ NULL,
181 /* 0x19 */ NULL,
182 /* 0x1a */ NULL,
183 /* 0x1b */ NULL,
184 /* 0x1c */ NULL,
185 /* 0x1d */ NULL,
186 /* 0x1e */ NULL,
187 /* 0x1f */ NULL,
188};
189
190static const u32 bass_table[41][5] = {
191 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
192 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
193 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
194 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
195 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
196 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
197 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
198 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
199 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
200 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
201 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
202 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
203 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
204 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
205 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
206 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
207 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
208 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
209 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
210 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
211 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
212 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
213 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
214 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
215 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
216 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
217 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
218 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
219 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
220 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
221 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
222 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
223 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
224 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
225 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
226 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
227 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
228 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
229 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
230 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
231 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
232};
233
234static const u32 treble_table[41][5] = {
235 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
236 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
237 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
238 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
239 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
240 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
241 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
242 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
243 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
244 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
245 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
246 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
247 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
248 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
249 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
250 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
251 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
252 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
253 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
254 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
255 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
256 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
257 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
258 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
259 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
260 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
261 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
262 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
263 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
264 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
265 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
266 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
267 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
268 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
269 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
270 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
271 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
272 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
273 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
274 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
275 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
276};
277
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100278/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279static const u32 db_table[101] = {
280 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
281 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
282 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
283 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
284 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
285 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
286 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
287 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
288 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
289 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
290 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
291 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
292 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
293 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
294 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
295 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
296 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
297 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
298 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
299 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
300 0x7fffffff,
301};
302
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100303/* EMU10k1/EMU10k2 DSP control db gain */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100304static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
Clemens Ladisch4daf7a02010-05-25 09:04:49 +0200305static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100306
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +0800307/* EMU10K1 bass/treble db gain */
308static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310static const u32 onoff_table[2] = {
311 0x00000000, 0x00000001
312};
313
314/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 * controls
316 */
317
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100318static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100320 struct snd_emu10k1_fx8010_ctl *ctl =
321 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 if (ctl->min == 0 && ctl->max == 1)
324 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
325 else
326 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
327 uinfo->count = ctl->vcount;
328 uinfo->value.integer.min = ctl->min;
329 uinfo->value.integer.max = ctl->max;
330 return 0;
331}
332
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100333static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100335 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
336 struct snd_emu10k1_fx8010_ctl *ctl =
337 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 unsigned long flags;
339 unsigned int i;
340
341 spin_lock_irqsave(&emu->reg_lock, flags);
342 for (i = 0; i < ctl->vcount; i++)
343 ucontrol->value.integer.value[i] = ctl->value[i];
344 spin_unlock_irqrestore(&emu->reg_lock, flags);
345 return 0;
346}
347
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100348static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100350 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
351 struct snd_emu10k1_fx8010_ctl *ctl =
352 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 unsigned long flags;
354 unsigned int nval, val;
355 unsigned int i, j;
356 int change = 0;
357
358 spin_lock_irqsave(&emu->reg_lock, flags);
359 for (i = 0; i < ctl->vcount; i++) {
360 nval = ucontrol->value.integer.value[i];
361 if (nval < ctl->min)
362 nval = ctl->min;
363 if (nval > ctl->max)
364 nval = ctl->max;
365 if (nval != ctl->value[i])
366 change = 1;
367 val = ctl->value[i] = nval;
368 switch (ctl->translation) {
369 case EMU10K1_GPR_TRANSLATION_NONE:
370 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
371 break;
372 case EMU10K1_GPR_TRANSLATION_TABLE100:
373 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
374 break;
375 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200376 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
377 change = -EIO;
378 goto __error;
379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 for (j = 0; j < 5; j++)
381 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
382 break;
383 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200384 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
385 change = -EIO;
386 goto __error;
387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 for (j = 0; j < 5; j++)
389 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
390 break;
391 case EMU10K1_GPR_TRANSLATION_ONOFF:
392 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
393 break;
394 }
395 }
396 __error:
397 spin_unlock_irqrestore(&emu->reg_lock, flags);
398 return change;
399}
400
401/*
402 * Interrupt handler
403 */
404
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100405static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100407 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
409 irq = emu->fx8010.irq_handlers;
410 while (irq) {
411 nirq = irq->next; /* irq ptr can be removed from list */
412 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
413 if (irq->handler)
414 irq->handler(emu, irq->private_data);
415 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
416 }
417 irq = nirq;
418 }
419}
420
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100421int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
422 snd_fx8010_irq_handler_t *handler,
423 unsigned char gpr_running,
424 void *private_data,
Takashi Iwai057666b2018-04-09 22:21:49 +0200425 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 unsigned long flags;
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 irq->handler = handler;
430 irq->gpr_running = gpr_running;
431 irq->private_data = private_data;
432 irq->next = NULL;
433 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
434 if (emu->fx8010.irq_handlers == NULL) {
435 emu->fx8010.irq_handlers = irq;
436 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
437 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
438 } else {
439 irq->next = emu->fx8010.irq_handlers;
440 emu->fx8010.irq_handlers = irq;
441 }
442 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 return 0;
444}
445
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100446int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
447 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100449 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 unsigned long flags;
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
453 if ((tmp = emu->fx8010.irq_handlers) == irq) {
454 emu->fx8010.irq_handlers = tmp->next;
455 if (emu->fx8010.irq_handlers == NULL) {
456 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
457 emu->dsp_interrupt = NULL;
458 }
459 } else {
460 while (tmp && tmp->next != irq)
461 tmp = tmp->next;
462 if (tmp)
463 tmp->next = tmp->next->next;
464 }
465 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 return 0;
467}
468
469/*************************************************************************
470 * EMU10K1 effect manager
471 *************************************************************************/
472
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100473static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
474 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 u32 op, u32 r, u32 a, u32 x, u32 y)
476{
477 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200478 if (snd_BUG_ON(*ptr >= 512))
479 return;
Clemens Ladisch4d233592005-09-05 10:35:20 +0200480 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 set_bit(*ptr, icode->code_valid);
482 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
483 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
484 (*ptr)++;
485}
486
487#define OP(icode, ptr, op, r, a, x, y) \
488 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
489
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100490static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
491 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 u32 op, u32 r, u32 a, u32 x, u32 y)
493{
494 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200495 if (snd_BUG_ON(*ptr >= 1024))
496 return;
Clemens Ladisch4d233592005-09-05 10:35:20 +0200497 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 set_bit(*ptr, icode->code_valid);
499 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
500 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
501 (*ptr)++;
502}
503
504#define A_OP(icode, ptr, op, r, a, x, y) \
505 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
506
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100507static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
510 snd_emu10k1_ptr_write(emu, pc, 0, data);
511}
512
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100513unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514{
515 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
516 return snd_emu10k1_ptr_read(emu, pc, 0);
517}
518
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100519static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200520 struct snd_emu10k1_fx8010_code *icode,
521 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522{
523 int gpr;
524 u32 val;
525
526 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
527 if (!test_bit(gpr, icode->gpr_valid))
528 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200529 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200530 val = *(__force u32 *)&icode->gpr_map[gpr];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200531 else if (get_user(val, &icode->gpr_map[gpr]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 return -EFAULT;
533 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
534 }
535 return 0;
536}
537
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100538static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
539 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 int gpr;
542 u32 val;
543
544 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
545 set_bit(gpr, icode->gpr_valid);
546 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
547 if (put_user(val, &icode->gpr_map[gpr]))
548 return -EFAULT;
549 }
550 return 0;
551}
552
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100553static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200554 struct snd_emu10k1_fx8010_code *icode,
555 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556{
557 int tram;
558 u32 addr, val;
559
560 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
561 if (!test_bit(tram, icode->tram_valid))
562 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200563 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200564 val = *(__force u32 *)&icode->tram_data_map[tram];
565 addr = *(__force u32 *)&icode->tram_addr_map[tram];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200566 } else {
567 if (get_user(val, &icode->tram_data_map[tram]) ||
568 get_user(addr, &icode->tram_addr_map[tram]))
569 return -EFAULT;
570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
572 if (!emu->audigy) {
573 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
574 } else {
575 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
576 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
577 }
578 }
579 return 0;
580}
581
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100582static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
583 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 int tram;
586 u32 val, addr;
587
588 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
589 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
590 set_bit(tram, icode->tram_valid);
591 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
592 if (!emu->audigy) {
593 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
594 } else {
595 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
596 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
597 }
598 if (put_user(val, &icode->tram_data_map[tram]) ||
599 put_user(addr, &icode->tram_addr_map[tram]))
600 return -EFAULT;
601 }
602 return 0;
603}
604
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100605static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200606 struct snd_emu10k1_fx8010_code *icode,
607 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 u32 pc, lo, hi;
610
611 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
612 if (!test_bit(pc / 2, icode->code_valid))
613 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200614 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200615 lo = *(__force u32 *)&icode->code[pc + 0];
616 hi = *(__force u32 *)&icode->code[pc + 1];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200617 } else {
618 if (get_user(lo, &icode->code[pc + 0]) ||
619 get_user(hi, &icode->code[pc + 1]))
620 return -EFAULT;
621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 snd_emu10k1_efx_write(emu, pc + 0, lo);
623 snd_emu10k1_efx_write(emu, pc + 1, hi);
624 }
625 return 0;
626}
627
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100628static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
629 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
631 u32 pc;
632
633 memset(icode->code_valid, 0, sizeof(icode->code_valid));
634 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
635 set_bit(pc / 2, icode->code_valid);
636 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
637 return -EFAULT;
638 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
639 return -EFAULT;
640 }
641 return 0;
642}
643
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100644static struct snd_emu10k1_fx8010_ctl *
645snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100647 struct snd_emu10k1_fx8010_ctl *ctl;
648 struct snd_kcontrol *kcontrol;
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200649
650 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 kcontrol = ctl->kcontrol;
652 if (kcontrol->id.iface == id->iface &&
653 !strcmp(kcontrol->id.name, id->name) &&
654 kcontrol->id.index == id->index)
655 return ctl;
656 }
657 return NULL;
658}
659
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100660#define MAX_TLV_SIZE 256
661
Takashi Iwaid42fe632017-05-10 17:11:34 +0200662static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100663{
664 unsigned int data[2];
665 unsigned int *tlv;
666
667 if (!_tlv)
668 return NULL;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200669 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200670 memcpy(data, (__force void *)_tlv, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200671 else if (copy_from_user(data, _tlv, sizeof(data)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100672 return NULL;
673 if (data[1] >= MAX_TLV_SIZE)
674 return NULL;
Takashi Iwai6735e572008-01-19 10:33:07 +0100675 tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100676 if (!tlv)
677 return NULL;
678 memcpy(tlv, data, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200679 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200680 memcpy(tlv + 2, (__force void *)(_tlv + 2), data[1]);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200681 } else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100682 kfree(tlv);
683 return NULL;
684 }
685 return tlv;
686}
687
688static int copy_gctl(struct snd_emu10k1 *emu,
689 struct snd_emu10k1_fx8010_control_gpr *gctl,
690 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200691 int idx, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100692{
693 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
694
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200695 if (emu->support_tlv) {
696 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200697 memcpy(gctl, (__force void *)&_gctl[idx], sizeof(*gctl));
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200698 else if (copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)))
699 return -EFAULT;
700 return 0;
701 }
702
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100703 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200704 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200705 memcpy(gctl, (__force void *)&octl[idx], sizeof(*octl));
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200706 else if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100707 return -EFAULT;
708 gctl->tlv = NULL;
709 return 0;
710}
711
712static int copy_gctl_to_user(struct snd_emu10k1 *emu,
713 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
714 struct snd_emu10k1_fx8010_control_gpr *gctl,
715 int idx)
716{
717 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
718
719 if (emu->support_tlv)
720 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
721
722 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
723 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
724}
725
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100726static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200727 struct snd_emu10k1_fx8010_code *icode,
728 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
730 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100731 struct snd_ctl_elem_id __user *_id;
732 struct snd_ctl_elem_id id;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100733 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 int err;
735
736 for (i = 0, _id = icode->gpr_del_controls;
737 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200738 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200739 id = *(__force struct snd_ctl_elem_id *)_id;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200740 else if (copy_from_user(&id, _id, sizeof(id)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 return -EFAULT;
742 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
743 return -ENOENT;
744 }
745 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
746 if (! gctl)
747 return -ENOMEM;
748 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100749 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200750 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
751 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 err = -EFAULT;
753 goto __error;
754 }
755 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
756 continue;
757 down_read(&emu->card->controls_rwsem);
758 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
759 up_read(&emu->card->controls_rwsem);
760 err = -EEXIST;
761 goto __error;
762 }
763 up_read(&emu->card->controls_rwsem);
764 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
765 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
766 err = -EINVAL;
767 goto __error;
768 }
769 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100770 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 /* FIXME: we need to check the WRITE access */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200772 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i,
773 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 err = -EFAULT;
775 goto __error;
776 }
777 }
778 __error:
779 kfree(gctl);
780 return err;
781}
782
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100783static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100785 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100787 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 kctl->private_value = 0;
789 list_del(&ctl->list);
790 kfree(ctl);
Markus Elfring31604d32014-11-03 14:54:36 +0100791 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792}
793
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100794static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200795 struct snd_emu10k1_fx8010_code *icode,
796 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100799 struct snd_emu10k1_fx8010_control_gpr *gctl;
800 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
801 struct snd_kcontrol_new knew;
802 struct snd_kcontrol *kctl;
803 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 int err = 0;
805
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100806 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
808 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
809 if (!val || !gctl || !nctl) {
810 err = -ENOMEM;
811 goto __error;
812 }
813
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100814 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200815 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
816 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 err = -EFAULT;
818 goto __error;
819 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200820 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
821 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
822 err = -EINVAL;
823 goto __error;
824 }
825 if (! gctl->id.name[0]) {
826 err = -EINVAL;
827 goto __error;
828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
830 memset(&knew, 0, sizeof(knew));
831 knew.iface = gctl->id.iface;
832 knew.name = gctl->id.name;
833 knew.index = gctl->id.index;
834 knew.device = gctl->id.device;
835 knew.subdevice = gctl->id.subdevice;
836 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwai63623642018-07-25 23:00:57 +0200837 knew.tlv.p = copy_tlv((__force const unsigned int __user *)gctl->tlv, in_kernel);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100838 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100839 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
840 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 knew.get = snd_emu10k1_gpr_ctl_get;
842 knew.put = snd_emu10k1_gpr_ctl_put;
843 memset(nctl, 0, sizeof(*nctl));
844 nctl->vcount = gctl->vcount;
845 nctl->count = gctl->count;
846 for (j = 0; j < 32; j++) {
847 nctl->gpr[j] = gctl->gpr[j];
848 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
849 val->value.integer.value[j] = gctl->value[j];
850 }
851 nctl->min = gctl->min;
852 nctl->max = gctl->max;
853 nctl->translation = gctl->translation;
854 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100855 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 if (ctl == NULL) {
857 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100858 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 goto __error;
860 }
861 knew.private_value = (unsigned long)ctl;
862 *ctl = *nctl;
863 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
864 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100865 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 goto __error;
867 }
868 kctl->private_free = snd_emu10k1_ctl_private_free;
869 ctl->kcontrol = kctl;
870 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
871 } else {
872 /* overwrite */
873 nctl->list = ctl->list;
874 nctl->kcontrol = ctl->kcontrol;
875 *ctl = *nctl;
876 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
877 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
878 }
879 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
880 }
881 __error:
882 kfree(nctl);
883 kfree(gctl);
884 kfree(val);
885 return err;
886}
887
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100888static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200889 struct snd_emu10k1_fx8010_code *icode,
890 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
892 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100893 struct snd_ctl_elem_id id;
894 struct snd_ctl_elem_id __user *_id;
895 struct snd_emu10k1_fx8010_ctl *ctl;
896 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
898 for (i = 0, _id = icode->gpr_del_controls;
899 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200900 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200901 id = *(__force struct snd_ctl_elem_id *)_id;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200902 else if (copy_from_user(&id, _id, sizeof(id)))
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200903 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 down_write(&card->controls_rwsem);
905 ctl = snd_emu10k1_look_for_ctl(emu, &id);
906 if (ctl)
907 snd_ctl_remove(card, ctl->kcontrol);
908 up_write(&card->controls_rwsem);
909 }
910 return 0;
911}
912
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100913static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
914 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915{
916 unsigned int i = 0, j;
917 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100918 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100919 struct snd_emu10k1_fx8010_ctl *ctl;
920 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
923 if (! gctl)
924 return -ENOMEM;
925
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200926 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100928 if (icode->gpr_list_controls &&
929 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 memset(gctl, 0, sizeof(*gctl));
931 id = &ctl->kcontrol->id;
932 gctl->id.iface = id->iface;
933 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
934 gctl->id.index = id->index;
935 gctl->id.device = id->device;
936 gctl->id.subdevice = id->subdevice;
937 gctl->vcount = ctl->vcount;
938 gctl->count = ctl->count;
939 for (j = 0; j < 32; j++) {
940 gctl->gpr[j] = ctl->gpr[j];
941 gctl->value[j] = ctl->value[j];
942 }
943 gctl->min = ctl->min;
944 gctl->max = ctl->max;
945 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100946 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
947 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 kfree(gctl);
949 return -EFAULT;
950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 i++;
952 }
953 }
954 icode->gpr_list_control_total = total;
955 kfree(gctl);
956 return 0;
957}
958
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100959static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200960 struct snd_emu10k1_fx8010_code *icode,
961 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 int err = 0;
964
Ingo Molnar62932df2006-01-16 16:34:20 +0100965 mutex_lock(&emu->fx8010.lock);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200966 err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
967 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 goto __error;
969 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
970 /* stop FX processor - this may be dangerous, but it's better to miss
971 some samples than generate wrong ones - [jk] */
972 if (emu->audigy)
973 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
974 else
975 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
976 /* ok, do the main job */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200977 err = snd_emu10k1_del_controls(emu, icode, in_kernel);
978 if (err < 0)
979 goto __error;
980 err = snd_emu10k1_gpr_poke(emu, icode, in_kernel);
981 if (err < 0)
982 goto __error;
983 err = snd_emu10k1_tram_poke(emu, icode, in_kernel);
984 if (err < 0)
985 goto __error;
986 err = snd_emu10k1_code_poke(emu, icode, in_kernel);
987 if (err < 0)
988 goto __error;
989 err = snd_emu10k1_add_controls(emu, icode, in_kernel);
990 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 goto __error;
992 /* start FX processor when the DSP code is updated */
993 if (emu->audigy)
994 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
995 else
996 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
997 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100998 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 return err;
1000}
1001
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001002static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
1003 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004{
1005 int err;
1006
Ingo Molnar62932df2006-01-16 16:34:20 +01001007 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
1009 /* ok, do the main job */
1010 err = snd_emu10k1_gpr_peek(emu, icode);
1011 if (err >= 0)
1012 err = snd_emu10k1_tram_peek(emu, icode);
1013 if (err >= 0)
1014 err = snd_emu10k1_code_peek(emu, icode);
1015 if (err >= 0)
1016 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +01001017 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return err;
1019}
1020
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001021static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
1022 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
1024 unsigned int i;
1025 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001026 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
1028 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1029 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001030 ipcm->substream = array_index_nospec(ipcm->substream,
1031 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if (ipcm->channels > 32)
1033 return -EINVAL;
1034 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001035 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 spin_lock_irq(&emu->reg_lock);
1037 if (pcm->opened) {
1038 err = -EBUSY;
1039 goto __error;
1040 }
1041 if (ipcm->channels == 0) { /* remove */
1042 pcm->valid = 0;
1043 } else {
1044 /* FIXME: we need to add universal code to the PCM transfer routine */
1045 if (ipcm->channels != 2) {
1046 err = -EINVAL;
1047 goto __error;
1048 }
1049 pcm->valid = 1;
1050 pcm->opened = 0;
1051 pcm->channels = ipcm->channels;
1052 pcm->tram_start = ipcm->tram_start;
1053 pcm->buffer_size = ipcm->buffer_size;
1054 pcm->gpr_size = ipcm->gpr_size;
1055 pcm->gpr_count = ipcm->gpr_count;
1056 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1057 pcm->gpr_ptr = ipcm->gpr_ptr;
1058 pcm->gpr_trigger = ipcm->gpr_trigger;
1059 pcm->gpr_running = ipcm->gpr_running;
1060 for (i = 0; i < pcm->channels; i++)
1061 pcm->etram[i] = ipcm->etram[i];
1062 }
1063 __error:
1064 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001065 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 return err;
1067}
1068
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001069static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1070 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
1072 unsigned int i;
1073 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001074 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1077 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001078 ipcm->substream = array_index_nospec(ipcm->substream,
1079 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001081 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 spin_lock_irq(&emu->reg_lock);
1083 ipcm->channels = pcm->channels;
1084 ipcm->tram_start = pcm->tram_start;
1085 ipcm->buffer_size = pcm->buffer_size;
1086 ipcm->gpr_size = pcm->gpr_size;
1087 ipcm->gpr_ptr = pcm->gpr_ptr;
1088 ipcm->gpr_count = pcm->gpr_count;
1089 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1090 ipcm->gpr_trigger = pcm->gpr_trigger;
1091 ipcm->gpr_running = pcm->gpr_running;
1092 for (i = 0; i < pcm->channels; i++)
1093 ipcm->etram[i] = pcm->etram[i];
1094 ipcm->res1 = ipcm->res2 = 0;
1095 ipcm->pad = 0;
1096 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001097 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return err;
1099}
1100
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001101#define SND_EMU10K1_GPR_CONTROLS 44
1102#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1104#define SND_EMU10K1_CAPTURE_CHANNELS 4
1105
Bill Pembertone23e7a12012-12-06 12:35:10 -05001106static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001107snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1108 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
1110 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1111 strcpy(ctl->id.name, name);
1112 ctl->vcount = ctl->count = 1;
1113 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001114 if (high_res_gpr_volume) {
1115 ctl->min = 0;
1116 ctl->max = 0x7fffffff;
1117 ctl->tlv = snd_emu10k1_db_linear;
1118 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1119 } else {
1120 ctl->min = 0;
1121 ctl->max = 100;
1122 ctl->tlv = snd_emu10k1_db_scale1;
1123 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125}
1126
Bill Pembertone23e7a12012-12-06 12:35:10 -05001127static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001128snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1129 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
1131 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1132 strcpy(ctl->id.name, name);
1133 ctl->vcount = ctl->count = 2;
1134 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1135 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001136 if (high_res_gpr_volume) {
1137 ctl->min = 0;
1138 ctl->max = 0x7fffffff;
1139 ctl->tlv = snd_emu10k1_db_linear;
1140 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1141 } else {
1142 ctl->min = 0;
1143 ctl->max = 100;
1144 ctl->tlv = snd_emu10k1_db_scale1;
1145 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147}
1148
Bill Pembertone23e7a12012-12-06 12:35:10 -05001149static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001150snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1151 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152{
1153 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1154 strcpy(ctl->id.name, name);
1155 ctl->vcount = ctl->count = 1;
1156 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1157 ctl->min = 0;
1158 ctl->max = 1;
1159 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1160}
1161
Bill Pembertone23e7a12012-12-06 12:35:10 -05001162static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001163snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1164 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
1166 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1167 strcpy(ctl->id.name, name);
1168 ctl->vcount = ctl->count = 2;
1169 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1170 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1171 ctl->min = 0;
1172 ctl->max = 1;
1173 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1174}
1175
Pavel Hofman13d45702007-06-11 12:21:20 +02001176/*
1177 * Used for emu1010 - conversion from 32-bit capture inputs from HANA
1178 * to 2 x 16-bit registers in audigy - their values are read via DMA.
1179 * Conversion is performed by Audigy DSP instructions of FX8010.
1180 */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001181static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1182 struct snd_emu10k1_fx8010_code *icode,
1183 u32 *ptr, int tmp, int bit_shifter16,
1184 int reg_in, int reg_out)
1185{
1186 A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
1187 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
1188 A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
1189 A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
1190 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
1191 A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
1192 A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
1193 A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
1194 return 1;
1195}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197/*
1198 * initial DSP configuration for Audigy
1199 */
1200
Bill Pembertone23e7a12012-12-06 12:35:10 -05001201static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 int err, i, z, gpr, nctl;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001204 int bit_shifter16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 const int playback = 10;
1206 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1207 const int stereo_mix = capture + 2;
1208 const int tmp = 0x88;
1209 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001210 struct snd_emu10k1_fx8010_code *icode = NULL;
1211 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001214 err = -ENOMEM;
1215 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1216 if (!icode)
1217 return err;
1218
1219 icode->gpr_map = (u_int32_t __user *) kcalloc(512 + 256 + 256 + 2 * 1024,
1220 sizeof(u_int32_t), GFP_KERNEL);
1221 if (!icode->gpr_map)
1222 goto __err_gpr;
1223 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1224 sizeof(*controls), GFP_KERNEL);
1225 if (!controls)
1226 goto __err_ctrls;
1227
Clemens Ladisch4d233592005-09-05 10:35:20 +02001228 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 icode->tram_data_map = icode->gpr_map + 512;
1231 icode->tram_addr_map = icode->tram_data_map + 256;
1232 icode->code = icode->tram_addr_map + 256;
1233
1234 /* clear free GPRs */
1235 for (i = 0; i < 512; i++)
1236 set_bit(i, icode->gpr_valid);
1237
1238 /* clear TRAM data & address lines */
1239 for (i = 0; i < 256; i++)
1240 set_bit(i, icode->tram_valid);
1241
1242 strcpy(icode->name, "Audigy DSP code for ALSA");
1243 ptr = 0;
1244 nctl = 0;
1245 gpr = stereo_mix + 10;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001246 gpr_map[gpr++] = 0x00007fff;
1247 gpr_map[gpr++] = 0x00008000;
1248 gpr_map[gpr++] = 0x0000ffff;
1249 bit_shifter16 = gpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251 /* stop FX processor */
1252 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1253
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001254#if 1
Pavel Hofman13d45702007-06-11 12:21:20 +02001255 /* PCM front Playback Volume (independent from stereo mix)
1256 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
1257 * where gpr contains attenuation from corresponding mixer control
1258 * (snd_emu10k1_init_stereo_control)
1259 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1261 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1262 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1263 gpr += 2;
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 /* PCM Surround Playback (independent from stereo mix) */
1266 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1267 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1268 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1269 gpr += 2;
1270
1271 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001272 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1274 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1275 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1276 gpr += 2;
1277 }
1278
1279 /* PCM Center Playback (independent from stereo mix) */
1280 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1281 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1282 gpr++;
1283
1284 /* PCM LFE Playback (independent from stereo mix) */
1285 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1286 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1287 gpr++;
1288
1289 /*
1290 * Stereo Mix
1291 */
1292 /* Wave (PCM) Playback Volume (will be renamed later) */
1293 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1294 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1295 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1296 gpr += 2;
1297
1298 /* Synth Playback */
1299 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1300 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1301 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1302 gpr += 2;
1303
1304 /* Wave (PCM) Capture */
1305 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1306 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1307 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1308 gpr += 2;
1309
1310 /* Synth Capture */
1311 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1312 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1313 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1314 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 /*
1317 * inputs
1318 */
1319#define A_ADD_VOLUME_IN(var,vol,input) \
1320A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1321
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001322 /* emu1212 DSP 0 and DSP 1 Capture */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001323 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001324 if (emu->card_capabilities->ca0108_chip) {
1325 /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
1326 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
1327 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
1328 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
1329 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
1330 } else {
1331 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1332 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1333 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001334 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1335 gpr += 2;
1336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 /* AC'97 Playback Volume - used only for mic (renamed later) */
1338 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1339 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1340 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1341 gpr += 2;
1342 /* AC'97 Capture Volume - used only for mic */
1343 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1344 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1345 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1346 gpr += 2;
1347
1348 /* mic capture buffer */
1349 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1350
1351 /* Audigy CD Playback Volume */
1352 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1353 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1354 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001355 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 gpr, 0);
1357 gpr += 2;
1358 /* Audigy CD Capture Volume */
1359 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1360 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1361 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001362 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 gpr, 0);
1364 gpr += 2;
1365
1366 /* Optical SPDIF Playback Volume */
1367 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1368 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001369 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 gpr += 2;
1371 /* Optical SPDIF Capture Volume */
1372 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1373 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001374 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 gpr += 2;
1376
1377 /* Line2 Playback Volume */
1378 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1379 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1380 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001381 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 gpr, 0);
1383 gpr += 2;
1384 /* Line2 Capture Volume */
1385 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1386 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1387 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001388 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 gpr, 0);
1390 gpr += 2;
1391
1392 /* Philips ADC Playback Volume */
1393 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1394 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1395 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1396 gpr += 2;
1397 /* Philips ADC Capture Volume */
1398 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1399 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1400 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1401 gpr += 2;
1402
1403 /* Aux2 Playback Volume */
1404 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1405 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1406 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001407 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 gpr, 0);
1409 gpr += 2;
1410 /* Aux2 Capture Volume */
1411 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1412 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1413 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001414 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 gpr, 0);
1416 gpr += 2;
1417
1418 /* Stereo Mix Front Playback Volume */
1419 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1420 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1421 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1422 gpr += 2;
1423
1424 /* Stereo Mix Surround Playback */
1425 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1426 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1427 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1428 gpr += 2;
1429
1430 /* Stereo Mix Center Playback */
1431 /* Center = sub = Left/2 + Right/2 */
1432 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1433 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1434 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1435 gpr++;
1436
1437 /* Stereo Mix LFE Playback */
1438 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1439 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1440 gpr++;
1441
Lee Revell2b637da2005-03-30 13:51:18 +02001442 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 /* Stereo Mix Side Playback */
1444 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1445 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1446 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1447 gpr += 2;
1448 }
1449
1450 /*
1451 * outputs
1452 */
1453#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1454#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1455 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1456
1457#define _A_SWITCH(icode, ptr, dst, src, sw) \
1458 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1459#define A_SWITCH(icode, ptr, dst, src, sw) \
1460 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1461#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1462 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1463#define A_SWITCH_NEG(icode, ptr, dst, src) \
1464 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1465
1466
1467 /*
1468 * Process tone control
1469 */
1470 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1471 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1472 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 */
1473 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 */
1474 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1475 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 +02001476 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 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 */
1478 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 */
1479 }
1480
1481
1482 ctl = &controls[nctl + 0];
1483 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1484 strcpy(ctl->id.name, "Tone Control - Bass");
1485 ctl->vcount = 2;
1486 ctl->count = 10;
1487 ctl->min = 0;
1488 ctl->max = 40;
1489 ctl->value[0] = ctl->value[1] = 20;
1490 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1491 ctl = &controls[nctl + 1];
1492 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1493 strcpy(ctl->id.name, "Tone Control - Treble");
1494 ctl->vcount = 2;
1495 ctl->count = 10;
1496 ctl->min = 0;
1497 ctl->max = 40;
1498 ctl->value[0] = ctl->value[1] = 20;
1499 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1500
1501#define BASS_GPR 0x8c
1502#define TREBLE_GPR 0x96
1503
1504 for (z = 0; z < 5; z++) {
1505 int j;
1506 for (j = 0; j < 2; j++) {
1507 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1508 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1509 }
1510 }
1511 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1512 int j, k, l, d;
1513 for (j = 0; j < 2; j++) { /* left/right */
1514 k = 0xb0 + (z * 8) + (j * 4);
1515 l = 0xe0 + (z * 8) + (j * 4);
1516 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1517
1518 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1519 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1520 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1521 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1522 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1523 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1524
1525 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1526 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1527 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1528 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1529 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1530 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1531
1532 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1533
1534 if (z == 2) /* center */
1535 break;
1536 }
1537 }
1538 nctl += 2;
1539
1540#undef BASS_GPR
1541#undef TREBLE_GPR
1542
1543 for (z = 0; z < 8; z++) {
1544 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1545 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1546 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1547 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1548 }
1549 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1550 gpr += 2;
1551
1552 /* Master volume (will be renamed later) */
1553 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));
1554 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));
1555 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));
1556 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));
1557 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));
1558 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));
1559 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));
1560 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));
1561 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1562 gpr += 2;
1563
1564 /* analog speakers */
1565 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1566 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1567 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1568 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001569 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1571
1572 /* headphone */
1573 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1574
1575 /* digital outputs */
1576 /* 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 +00001577 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001578 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
Takashi Iwai6f002b02014-02-25 17:02:09 +01001579 dev_info(emu->card->dev, "EMU outputs on\n");
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001580 for (z = 0; z < 8; z++) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001581 if (emu->card_capabilities->ca0108_chip) {
1582 A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1583 } else {
1584 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1585 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001586 }
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 /* IEC958 Optical Raw Playback Switch */
1590 gpr_map[gpr++] = 0;
1591 gpr_map[gpr++] = 0x1008;
1592 gpr_map[gpr++] = 0xffff0000;
1593 for (z = 0; z < 2; z++) {
1594 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1595 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1596 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1597 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1598 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1599 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1600 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1601 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1602 /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
Takashi Iwai6f002b02014-02-25 17:02:09 +01001603 dev_info(emu->card->dev,
1604 "Installing spdif_bug patch: %s\n",
1605 emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1607 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1608 } else {
1609 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1610 }
1611 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001612 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 -07001613 gpr += 2;
1614
1615 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1616 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1617 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1618
1619 /* ADC buffer */
1620#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1621 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1622#else
1623 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1624 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1625#endif
1626
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001627 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001628 if (emu->card_capabilities->ca0108_chip) {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001629 dev_info(emu->card->dev, "EMU2 inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001630 for (z = 0; z < 0x10; z++) {
1631 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
1632 bit_shifter16,
1633 A3_EMU32IN(z),
1634 A_FXBUS2(z*2) );
1635 }
1636 } else {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001637 dev_info(emu->card->dev, "EMU inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001638 /* Capture 16 (originally 8) channels of S32_LE sound */
1639
Takashi Iwai28a97c12009-02-05 16:08:14 +01001640 /*
Takashi Iwai6f002b02014-02-25 17:02:09 +01001641 dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
Takashi Iwai28a97c12009-02-05 16:08:14 +01001642 gpr, tmp);
1643 */
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001644 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1645 /* A_P16VIN(0) is delayed by one sample,
1646 * so all other A_P16VIN channels will need to also be delayed
1647 */
1648 /* Left ADC in. 1 of 2 */
1649 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1650 /* Right ADC in 1 of 2 */
1651 gpr_map[gpr++] = 0x00000000;
1652 /* Delaying by one sample: instead of copying the input
1653 * value A_P16VIN to output A_FXBUS2 as in the first channel,
1654 * we use an auxiliary register, delaying the value by one
1655 * sample
1656 */
1657 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1658 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1659 gpr_map[gpr++] = 0x00000000;
1660 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1661 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
1662 gpr_map[gpr++] = 0x00000000;
1663 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
1664 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1665 /* For 96kHz mode */
1666 /* Left ADC in. 2 of 2 */
1667 gpr_map[gpr++] = 0x00000000;
1668 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1669 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1670 /* Right ADC in 2 of 2 */
1671 gpr_map[gpr++] = 0x00000000;
1672 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1673 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
1674 gpr_map[gpr++] = 0x00000000;
1675 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
1676 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
1677 gpr_map[gpr++] = 0x00000000;
1678 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
1679 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1680 /* Pavel Hofman - we still have voices, A_FXBUS2s, and
1681 * A_P16VINs available -
1682 * let's add 8 more capture channels - total of 16
1683 */
1684 gpr_map[gpr++] = 0x00000000;
1685 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1686 bit_shifter16,
1687 A_GPR(gpr - 1),
1688 A_FXBUS2(0x10));
1689 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
1690 A_C_00000000, A_C_00000000);
1691 gpr_map[gpr++] = 0x00000000;
1692 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1693 bit_shifter16,
1694 A_GPR(gpr - 1),
1695 A_FXBUS2(0x12));
1696 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
1697 A_C_00000000, A_C_00000000);
1698 gpr_map[gpr++] = 0x00000000;
1699 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1700 bit_shifter16,
1701 A_GPR(gpr - 1),
1702 A_FXBUS2(0x14));
1703 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
1704 A_C_00000000, A_C_00000000);
1705 gpr_map[gpr++] = 0x00000000;
1706 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1707 bit_shifter16,
1708 A_GPR(gpr - 1),
1709 A_FXBUS2(0x16));
1710 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
1711 A_C_00000000, A_C_00000000);
1712 gpr_map[gpr++] = 0x00000000;
1713 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1714 bit_shifter16,
1715 A_GPR(gpr - 1),
1716 A_FXBUS2(0x18));
1717 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
1718 A_C_00000000, A_C_00000000);
1719 gpr_map[gpr++] = 0x00000000;
1720 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1721 bit_shifter16,
1722 A_GPR(gpr - 1),
1723 A_FXBUS2(0x1a));
1724 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
1725 A_C_00000000, A_C_00000000);
1726 gpr_map[gpr++] = 0x00000000;
1727 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1728 bit_shifter16,
1729 A_GPR(gpr - 1),
1730 A_FXBUS2(0x1c));
1731 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
1732 A_C_00000000, A_C_00000000);
1733 gpr_map[gpr++] = 0x00000000;
1734 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1735 bit_shifter16,
1736 A_GPR(gpr - 1),
1737 A_FXBUS2(0x1e));
1738 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
1739 A_C_00000000, A_C_00000000);
1740 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001741
1742#if 0
1743 for (z = 4; z < 8; z++) {
1744 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1745 }
1746 for (z = 0xc; z < 0x10; z++) {
1747 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1748 }
1749#endif
1750 } else {
1751 /* EFX capture - capture the 16 EXTINs */
1752 /* Capture 16 channels of S16_LE sound */
1753 for (z = 0; z < 16; z++) {
1754 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 }
1757
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001758#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 /*
1760 * ok, set up done..
1761 */
1762
1763 if (gpr > tmp) {
1764 snd_BUG();
1765 err = -EIO;
1766 goto __err;
1767 }
1768 /* clear remaining instruction memory */
1769 while (ptr < 0x400)
1770 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001773 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001774 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02001775 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001776 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001778__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001780__err_ctrls:
1781 kfree((void __force *)icode->gpr_map);
1782__err_gpr:
1783 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 return err;
1785}
1786
1787
1788/*
1789 * initial DSP configuration for Emu10k1
1790 */
1791
1792/* when volume = max, then copy only to avoid volume modification */
1793/* with iMAC0 (negative values) */
Bill Pembertone23e7a12012-12-06 12:35:10 -05001794static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795{
1796 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1797 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1798 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1799 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1800}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001801static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802{
1803 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1804 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1805 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1806 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1807 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1808}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001809static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810{
1811 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1812 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1813 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1814 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1815 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1816}
1817
1818#define VOLUME(icode, ptr, dst, src, vol) \
1819 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1820#define VOLUME_IN(icode, ptr, dst, src, vol) \
1821 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1822#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1823 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1824#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1825 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1826#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1827 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1828#define _SWITCH(icode, ptr, dst, src, sw) \
1829 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1830#define SWITCH(icode, ptr, dst, src, sw) \
1831 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1832#define SWITCH_IN(icode, ptr, dst, src, sw) \
1833 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1834#define _SWITCH_NEG(icode, ptr, dst, src) \
1835 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1836#define SWITCH_NEG(icode, ptr, dst, src) \
1837 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1838
1839
Bill Pembertone23e7a12012-12-06 12:35:10 -05001840static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
1842 int err, i, z, gpr, tmp, playback, capture;
1843 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001844 struct snd_emu10k1_fx8010_code *icode;
1845 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1846 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001849 err = -ENOMEM;
1850 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1851 if (!icode)
1852 return err;
1853
1854 icode->gpr_map = (u_int32_t __user *) kcalloc(256 + 160 + 160 + 2 * 512,
1855 sizeof(u_int32_t), GFP_KERNEL);
1856 if (!icode->gpr_map)
1857 goto __err_gpr;
1858
1859 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1860 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1861 GFP_KERNEL);
1862 if (!controls)
1863 goto __err_ctrls;
1864
1865 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
1866 if (!ipcm)
1867 goto __err_ipcm;
1868
Clemens Ladisch4d233592005-09-05 10:35:20 +02001869 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 icode->tram_data_map = icode->gpr_map + 256;
1872 icode->tram_addr_map = icode->tram_data_map + 160;
1873 icode->code = icode->tram_addr_map + 160;
1874
1875 /* clear free GPRs */
1876 for (i = 0; i < 256; i++)
1877 set_bit(i, icode->gpr_valid);
1878
1879 /* clear TRAM data & address lines */
1880 for (i = 0; i < 160; i++)
1881 set_bit(i, icode->tram_valid);
1882
1883 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1884 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001885 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 playback = SND_EMU10K1_INPUTS;
1887 /* we have 6 playback channels and tone control doubles */
1888 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1889 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1890 tmp = 0x88; /* we need 4 temporary GPR */
1891 /* from 0x8c to 0xff is the area for tone control */
1892
1893 /* stop FX processor */
1894 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1895
1896 /*
1897 * Process FX Buses
1898 */
1899 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1900 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1901 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1902 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1903 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1904 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1905 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1906 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1907 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1908 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001909 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1910 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
1912 /* Raw S/PDIF PCM */
1913 ipcm->substream = 0;
1914 ipcm->channels = 2;
1915 ipcm->tram_start = 0;
1916 ipcm->buffer_size = (64 * 1024) / 2;
1917 ipcm->gpr_size = gpr++;
1918 ipcm->gpr_ptr = gpr++;
1919 ipcm->gpr_count = gpr++;
1920 ipcm->gpr_tmpcount = gpr++;
1921 ipcm->gpr_trigger = gpr++;
1922 ipcm->gpr_running = gpr++;
1923 ipcm->etram[0] = 0;
1924 ipcm->etram[1] = 1;
1925
1926 gpr_map[gpr + 0] = 0xfffff000;
1927 gpr_map[gpr + 1] = 0xffff0000;
1928 gpr_map[gpr + 2] = 0x70000000;
1929 gpr_map[gpr + 3] = 0x00000007;
1930 gpr_map[gpr + 4] = 0x001f << 11;
1931 gpr_map[gpr + 5] = 0x001c << 11;
1932 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1933 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1934 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1935 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1936 gpr_map[gpr + 10] = 1<<11;
1937 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1938 gpr_map[gpr + 12] = 0;
1939
1940 /* if the trigger flag is not set, skip */
1941 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1942 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1943 /* if the running flag is set, we're running */
1944 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1945 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1946 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1947 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1948 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1949 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1950 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1951
1952 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1953 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1954 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1955 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1956
1957 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1958 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1959 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1960 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1961 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1962
1963 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1964 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1965 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1966 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1967 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1968
1969 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1970 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1971 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1972 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1973 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1974
1975 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1976 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1977 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1978 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1979 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1980
1981 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1982 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1983
1984 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1985 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1986
1987 /* 24: */
1988 gpr += 13;
1989
1990 /* Wave Playback Volume */
1991 for (z = 0; z < 2; z++)
1992 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1993 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1994 gpr += 2;
1995
1996 /* Wave Surround Playback Volume */
1997 for (z = 0; z < 2; z++)
1998 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1999 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
2000 gpr += 2;
2001
2002 /* Wave Center/LFE Playback Volume */
2003 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
2004 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
2005 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
2006 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
2007 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
2008 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
2009
2010 /* Wave Capture Volume + Switch */
2011 for (z = 0; z < 2; z++) {
2012 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
2013 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
2014 }
2015 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
2016 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
2017 gpr += 4;
2018
2019 /* Synth Playback Volume */
2020 for (z = 0; z < 2; z++)
2021 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
2022 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
2023 gpr += 2;
2024
2025 /* Synth Capture Volume + Switch */
2026 for (z = 0; z < 2; z++) {
2027 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
2028 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2029 }
2030 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
2031 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
2032 gpr += 4;
2033
2034 /* Surround Digital Playback Volume (renamed later without Digital) */
2035 for (z = 0; z < 2; z++)
2036 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
2037 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
2038 gpr += 2;
2039
2040 /* Surround Capture Volume + Switch */
2041 for (z = 0; z < 2; z++) {
2042 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
2043 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2044 }
2045 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
2046 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
2047 gpr += 4;
2048
2049 /* Center Playback Volume (renamed later without Digital) */
2050 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
2051 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
2052
2053 /* LFE Playback Volume + Switch (renamed later without Digital) */
2054 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
2055 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
2056
Mikael Magnussonedf8e452005-09-13 11:32:58 +02002057 /* Front Playback Volume */
2058 for (z = 0; z < 2; z++)
2059 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
2060 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
2061 gpr += 2;
2062
2063 /* Front Capture Volume + Switch */
2064 for (z = 0; z < 2; z++) {
2065 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
2066 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2067 }
2068 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2069 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2070 gpr += 3;
2071
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 /*
2073 * Process inputs
2074 */
2075
2076 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
2077 /* AC'97 Playback Volume */
2078 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
2079 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
2080 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
2081 /* AC'97 Capture Volume */
2082 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
2083 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
2084 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
2085 }
2086
2087 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
2088 /* IEC958 TTL Playback Volume */
2089 for (z = 0; z < 2; z++)
2090 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002091 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 gpr += 2;
2093
2094 /* IEC958 TTL Capture Volume + Switch */
2095 for (z = 0; z < 2; z++) {
2096 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
2097 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2098 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002099 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
2100 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 -07002101 gpr += 4;
2102 }
2103
2104 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
2105 /* Zoom Video Playback Volume */
2106 for (z = 0; z < 2; z++)
2107 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
2108 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
2109 gpr += 2;
2110
2111 /* Zoom Video Capture Volume + Switch */
2112 for (z = 0; z < 2; z++) {
2113 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
2114 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2115 }
2116 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
2117 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
2118 gpr += 4;
2119 }
2120
2121 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
2122 /* IEC958 Optical Playback Volume */
2123 for (z = 0; z < 2; z++)
2124 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002125 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 gpr += 2;
2127
2128 /* IEC958 Optical Capture Volume */
2129 for (z = 0; z < 2; z++) {
2130 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
2131 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2132 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002133 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
2134 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 -07002135 gpr += 4;
2136 }
2137
2138 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
2139 /* Line LiveDrive Playback Volume */
2140 for (z = 0; z < 2; z++)
2141 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
2142 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
2143 gpr += 2;
2144
2145 /* Line LiveDrive Capture Volume + Switch */
2146 for (z = 0; z < 2; z++) {
2147 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
2148 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2149 }
2150 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
2151 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
2152 gpr += 4;
2153 }
2154
2155 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
2156 /* IEC958 Coax Playback Volume */
2157 for (z = 0; z < 2; z++)
2158 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002159 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 gpr += 2;
2161
2162 /* IEC958 Coax Capture Volume + Switch */
2163 for (z = 0; z < 2; z++) {
2164 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2165 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2166 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002167 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2168 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 -07002169 gpr += 4;
2170 }
2171
2172 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2173 /* Line LiveDrive Playback Volume */
2174 for (z = 0; z < 2; z++)
2175 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2176 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2177 controls[i-1].id.index = 1;
2178 gpr += 2;
2179
2180 /* Line LiveDrive Capture Volume */
2181 for (z = 0; z < 2; z++) {
2182 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2183 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2184 }
2185 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2186 controls[i-1].id.index = 1;
2187 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2188 controls[i-1].id.index = 1;
2189 gpr += 4;
2190 }
2191
2192 /*
2193 * Process tone control
2194 */
2195 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2196 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2197 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2198 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2199 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2200 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2201
2202 ctl = &controls[i + 0];
2203 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2204 strcpy(ctl->id.name, "Tone Control - Bass");
2205 ctl->vcount = 2;
2206 ctl->count = 10;
2207 ctl->min = 0;
2208 ctl->max = 40;
2209 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002210 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2212 ctl = &controls[i + 1];
2213 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2214 strcpy(ctl->id.name, "Tone Control - Treble");
2215 ctl->vcount = 2;
2216 ctl->count = 10;
2217 ctl->min = 0;
2218 ctl->max = 40;
2219 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002220 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2222
2223#define BASS_GPR 0x8c
2224#define TREBLE_GPR 0x96
2225
2226 for (z = 0; z < 5; z++) {
2227 int j;
2228 for (j = 0; j < 2; j++) {
2229 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2230 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2231 }
2232 }
2233 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2234 int j, k, l, d;
2235 for (j = 0; j < 2; j++) { /* left/right */
2236 k = 0xa0 + (z * 8) + (j * 4);
2237 l = 0xd0 + (z * 8) + (j * 4);
2238 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2239
2240 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2241 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2242 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2243 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2244 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2245 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2246
2247 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2248 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2249 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2250 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2251 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2252 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2253
2254 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2255
2256 if (z == 2) /* center */
2257 break;
2258 }
2259 }
2260 i += 2;
2261
2262#undef BASS_GPR
2263#undef TREBLE_GPR
2264
2265 for (z = 0; z < 6; z++) {
2266 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2267 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2268 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2269 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2270 }
2271 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2272 gpr += 2;
2273
2274 /*
2275 * Process outputs
2276 */
2277 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2278 /* AC'97 Playback Volume */
2279
2280 for (z = 0; z < 2; z++)
2281 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2282 }
2283
2284 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2285 /* IEC958 Optical Raw Playback Switch */
2286
2287 for (z = 0; z < 2; z++) {
2288 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2289 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2290 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2291 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2292#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2293 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2294#endif
2295 }
2296
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002297 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 -07002298 gpr += 2;
2299 }
2300
2301 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2302 /* Headphone Playback Volume */
2303
2304 for (z = 0; z < 2; z++) {
2305 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2306 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2307 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2308 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2309 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2310 }
2311
2312 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2313 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2314 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2315 controls[i-1].id.index = 1;
2316 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2317 controls[i-1].id.index = 1;
2318
2319 gpr += 4;
2320 }
2321
2322 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2323 for (z = 0; z < 2; z++)
2324 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2325
2326 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2327 for (z = 0; z < 2; z++)
2328 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2329
2330 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2331#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2332 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2333 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2334#else
2335 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2336 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2337#endif
2338 }
2339
2340 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2341#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2342 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2343 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2344#else
2345 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2346 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2347#endif
2348 }
2349
2350#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2351 for (z = 0; z < 2; z++)
2352 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2353#endif
2354
2355 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2356 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2357
2358 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002359 if (emu->card_capabilities->sblive51) {
2360 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2361 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2362 *
2363 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2364 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2365 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2366 * channel. Multitrack recorders will still see the center/lfe output signal
2367 * on the second and third channels.
2368 */
2369 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2370 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2371 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2372 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2373 for (z = 4; z < 14; z++)
2374 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2375 } else {
2376 for (z = 0; z < 16; z++)
2377 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 }
Lee Revell2b637da2005-03-30 13:51:18 +02002379
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
2381 if (gpr > tmp) {
2382 snd_BUG();
2383 err = -EIO;
2384 goto __err;
2385 }
2386 if (i > SND_EMU10K1_GPR_CONTROLS) {
2387 snd_BUG();
2388 err = -EIO;
2389 goto __err;
2390 }
2391
2392 /* clear remaining instruction memory */
2393 while (ptr < 0x200)
2394 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2395
2396 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2397 goto __err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002399 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002400 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02002401 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002402 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 if (err >= 0)
2404 err = snd_emu10k1_ipcm_poke(emu, ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002405__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 kfree(ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002407__err_ipcm:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002409__err_ctrls:
2410 kfree((void __force *)icode->gpr_map);
2411__err_gpr:
2412 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 return err;
2414}
2415
Bill Pembertone23e7a12012-12-06 12:35:10 -05002416int snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417{
Takashi Iwai09668b42005-11-17 16:14:10 +01002418 spin_lock_init(&emu->fx8010.irq_lock);
2419 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 if (emu->audigy)
2421 return _snd_emu10k1_audigy_init_efx(emu);
2422 else
2423 return _snd_emu10k1_init_efx(emu);
2424}
2425
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002426void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427{
2428 /* stop processor */
2429 if (emu->audigy)
2430 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2431 else
2432 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2433}
2434
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002435#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002436int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002438 if (output < 0 || output >= 6)
2439 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2441 return 0;
2442}
2443
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002444int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002446 if (output < 0 || output >= 6)
2447 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2449 return 0;
2450}
2451#endif
2452
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002453int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454{
2455 u8 size_reg = 0;
2456
2457 /* size is in samples */
2458 if (size != 0) {
2459 size = (size - 1) >> 13;
2460
2461 while (size) {
2462 size >>= 1;
2463 size_reg++;
2464 }
2465 size = 0x2000 << size_reg;
2466 }
2467 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2468 return 0;
2469 spin_lock_irq(&emu->emu_lock);
2470 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2471 spin_unlock_irq(&emu->emu_lock);
2472 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2473 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2474 if (emu->fx8010.etram_pages.area != NULL) {
2475 snd_dma_free_pages(&emu->fx8010.etram_pages);
2476 emu->fx8010.etram_pages.area = NULL;
2477 emu->fx8010.etram_pages.bytes = 0;
2478 }
2479
2480 if (size > 0) {
2481 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2482 size * 2, &emu->fx8010.etram_pages) < 0)
2483 return -ENOMEM;
2484 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2485 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2486 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2487 spin_lock_irq(&emu->emu_lock);
2488 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002489 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 }
2491
2492 return 0;
2493}
2494
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002495static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496{
2497 return 0;
2498}
2499
2500static void copy_string(char *dst, char *src, char *null, int idx)
2501{
2502 if (src == NULL)
2503 sprintf(dst, "%s %02X", null, idx);
2504 else
2505 strcpy(dst, src);
2506}
2507
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002508static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002509 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510{
2511 char **fxbus, **extin, **extout;
2512 unsigned short fxbus_mask, extin_mask, extout_mask;
2513 int res;
2514
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 info->internal_tram_size = emu->fx8010.itram_size;
2516 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2517 fxbus = fxbuses;
2518 extin = emu->audigy ? audigy_ins : creative_ins;
2519 extout = emu->audigy ? audigy_outs : creative_outs;
2520 fxbus_mask = emu->fx8010.fxbus_mask;
2521 extin_mask = emu->fx8010.extin_mask;
2522 extout_mask = emu->fx8010.extout_mask;
2523 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2524 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2525 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2526 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2527 }
2528 for (res = 16; res < 32; res++, extout++)
2529 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2530 info->gpr_controls = emu->fx8010.gpr_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531}
2532
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002533static 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 -07002534{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002535 struct snd_emu10k1 *emu = hw->private_data;
2536 struct snd_emu10k1_fx8010_info *info;
2537 struct snd_emu10k1_fx8010_code *icode;
2538 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 unsigned int addr;
2540 void __user *argp = (void __user *)arg;
2541 int res;
2542
2543 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002544 case SNDRV_EMU10K1_IOCTL_PVERSION:
2545 emu->support_tlv = 1;
2546 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 case SNDRV_EMU10K1_IOCTL_INFO:
Willy Tarreau49434c6c2018-09-08 08:12:21 +02002548 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 if (!info)
2550 return -ENOMEM;
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002551 snd_emu10k1_fx8010_info(emu, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 if (copy_to_user(argp, info, sizeof(*info))) {
2553 kfree(info);
2554 return -EFAULT;
2555 }
2556 kfree(info);
2557 return 0;
2558 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2559 if (!capable(CAP_SYS_ADMIN))
2560 return -EPERM;
Li Zefan336500f2009-04-10 09:44:31 +08002561
2562 icode = memdup_user(argp, sizeof(*icode));
2563 if (IS_ERR(icode))
2564 return PTR_ERR(icode);
Takashi Iwaid42fe632017-05-10 17:11:34 +02002565 res = snd_emu10k1_icode_poke(emu, icode, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 kfree(icode);
2567 return res;
2568 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002569 icode = memdup_user(argp, sizeof(*icode));
2570 if (IS_ERR(icode))
2571 return PTR_ERR(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 res = snd_emu10k1_icode_peek(emu, icode);
2573 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2574 kfree(icode);
2575 return -EFAULT;
2576 }
2577 kfree(icode);
2578 return res;
2579 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Li Zefan336500f2009-04-10 09:44:31 +08002580 ipcm = memdup_user(argp, sizeof(*ipcm));
2581 if (IS_ERR(ipcm))
2582 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2584 kfree(ipcm);
2585 return res;
2586 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002587 ipcm = memdup_user(argp, sizeof(*ipcm));
2588 if (IS_ERR(ipcm))
2589 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2591 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2592 kfree(ipcm);
2593 return -EFAULT;
2594 }
2595 kfree(ipcm);
2596 return res;
2597 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2598 if (!capable(CAP_SYS_ADMIN))
2599 return -EPERM;
2600 if (get_user(addr, (unsigned int __user *)argp))
2601 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002602 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002604 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 return res;
2606 case SNDRV_EMU10K1_IOCTL_STOP:
2607 if (!capable(CAP_SYS_ADMIN))
2608 return -EPERM;
2609 if (emu->audigy)
2610 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2611 else
2612 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2613 return 0;
2614 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2615 if (!capable(CAP_SYS_ADMIN))
2616 return -EPERM;
2617 if (emu->audigy)
2618 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2619 else
2620 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2621 return 0;
2622 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2623 if (!capable(CAP_SYS_ADMIN))
2624 return -EPERM;
2625 if (emu->audigy)
2626 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2627 else
2628 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2629 udelay(10);
2630 if (emu->audigy)
2631 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2632 else
2633 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2634 return 0;
2635 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2636 if (!capable(CAP_SYS_ADMIN))
2637 return -EPERM;
2638 if (get_user(addr, (unsigned int __user *)argp))
2639 return -EFAULT;
2640 if (addr > 0x1ff)
2641 return -EINVAL;
2642 if (emu->audigy)
2643 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2644 else
2645 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2646 udelay(10);
2647 if (emu->audigy)
2648 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2649 else
2650 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2651 return 0;
2652 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2653 if (emu->audigy)
2654 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2655 else
2656 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2657 if (put_user(addr, (unsigned int __user *)argp))
2658 return -EFAULT;
2659 return 0;
2660 }
2661 return -ENOTTY;
2662}
2663
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002664static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665{
2666 return 0;
2667}
2668
Lars-Peter Clausenbb814c32015-01-02 12:24:49 +01002669int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002671 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 int err;
2673
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2675 return err;
2676 strcpy(hw->name, "EMU10K1 (FX8010)");
2677 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2678 hw->ops.open = snd_emu10k1_fx8010_open;
2679 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2680 hw->ops.release = snd_emu10k1_fx8010_release;
2681 hw->private_data = emu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return 0;
2683}
Takashi Iwai09668b42005-11-17 16:14:10 +01002684
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002685#ifdef CONFIG_PM_SLEEP
Bill Pembertone23e7a12012-12-06 12:35:10 -05002686int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
Takashi Iwai09668b42005-11-17 16:14:10 +01002687{
2688 int len;
2689
2690 len = emu->audigy ? 0x200 : 0x100;
Kees Cook6da2ec52018-06-12 13:55:00 -07002691 emu->saved_gpr = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002692 if (! emu->saved_gpr)
2693 return -ENOMEM;
2694 len = emu->audigy ? 0x100 : 0xa0;
Kees Cook6da2ec52018-06-12 13:55:00 -07002695 emu->tram_val_saved = kmalloc_array(len, 4, GFP_KERNEL);
2696 emu->tram_addr_saved = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002697 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2698 return -ENOMEM;
2699 len = emu->audigy ? 2 * 1024 : 2 * 512;
Kees Cook42bc47b2018-06-12 14:27:11 -07002700 emu->saved_icode = vmalloc(array_size(len, 4));
Takashi Iwai09668b42005-11-17 16:14:10 +01002701 if (! emu->saved_icode)
2702 return -ENOMEM;
2703 return 0;
2704}
2705
2706void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2707{
2708 kfree(emu->saved_gpr);
2709 kfree(emu->tram_val_saved);
2710 kfree(emu->tram_addr_saved);
2711 vfree(emu->saved_icode);
2712}
2713
2714/*
2715 * save/restore GPR, TRAM and codes
2716 */
2717void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2718{
2719 int i, len;
2720
2721 len = emu->audigy ? 0x200 : 0x100;
2722 for (i = 0; i < len; i++)
2723 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2724
2725 len = emu->audigy ? 0x100 : 0xa0;
2726 for (i = 0; i < len; i++) {
2727 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2728 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2729 if (emu->audigy) {
2730 emu->tram_addr_saved[i] >>= 12;
2731 emu->tram_addr_saved[i] |=
2732 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2733 }
2734 }
2735
2736 len = emu->audigy ? 2 * 1024 : 2 * 512;
2737 for (i = 0; i < len; i++)
2738 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2739}
2740
2741void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2742{
2743 int i, len;
2744
2745 /* set up TRAM */
2746 if (emu->fx8010.etram_pages.bytes > 0) {
2747 unsigned size, size_reg = 0;
2748 size = emu->fx8010.etram_pages.bytes / 2;
2749 size = (size - 1) >> 13;
2750 while (size) {
2751 size >>= 1;
2752 size_reg++;
2753 }
2754 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2755 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2756 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2757 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2758 }
2759
2760 if (emu->audigy)
2761 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2762 else
2763 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2764
2765 len = emu->audigy ? 0x200 : 0x100;
2766 for (i = 0; i < len; i++)
2767 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2768
2769 len = emu->audigy ? 0x100 : 0xa0;
2770 for (i = 0; i < len; i++) {
2771 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2772 emu->tram_val_saved[i]);
2773 if (! emu->audigy)
2774 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2775 emu->tram_addr_saved[i]);
2776 else {
2777 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2778 emu->tram_addr_saved[i] << 12);
2779 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2780 emu->tram_addr_saved[i] >> 20);
2781 }
2782 }
2783
2784 len = emu->audigy ? 2 * 1024 : 2 * 512;
2785 for (i = 0; i < len; i++)
2786 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2787
2788 /* start FX processor when the DSP code is updated */
2789 if (emu->audigy)
2790 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2791 else
2792 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2793}
2794#endif