blob: e053f0d58bdd08fb72999e6b60cdf6a7cb44d3aa [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02003 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Creative Labs, Inc.
5 * Routines for effect processor FX8010
6 *
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01007 * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk>
8 * Added EMU 1010 support.
9 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * BUGS:
11 * --
12 *
13 * TODO:
14 * --
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 */
16
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/pci.h>
Randy.Dunlapc59ede72006-01-11 12:17:46 -080018#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/delay.h>
20#include <linux/slab.h>
Andreas Schwabbd01e7b2005-12-05 15:12:20 +010021#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010023#include <linux/mutex.h>
Clemens Ladisch4daf7a02010-05-25 09:04:49 +020024#include <linux/moduleparam.h>
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -060025#include <linux/nospec.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010026
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <sound/core.h>
James Courtier-Dutton31508f82006-07-22 17:02:10 +010028#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <sound/emu10k1.h>
30
31#if 0 /* for testing purposes - digital out -> capture */
32#define EMU10K1_CAPTURE_DIGITAL_OUT
33#endif
34#if 0 /* for testing purposes - set S/PDIF to AC3 output */
35#define EMU10K1_SET_AC3_IEC958
36#endif
37#if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
38#define EMU10K1_CENTER_LFE_FROM_FRONT
39#endif
40
Clemens Ladisch4daf7a02010-05-25 09:04:49 +020041static bool high_res_gpr_volume;
42module_param(high_res_gpr_volume, bool, 0444);
43MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045/*
46 * Tables
47 */
48
49static char *fxbuses[16] = {
50 /* 0x00 */ "PCM Left",
51 /* 0x01 */ "PCM Right",
52 /* 0x02 */ "PCM Surround Left",
53 /* 0x03 */ "PCM Surround Right",
54 /* 0x04 */ "MIDI Left",
55 /* 0x05 */ "MIDI Right",
56 /* 0x06 */ "Center",
57 /* 0x07 */ "LFE",
58 /* 0x08 */ NULL,
59 /* 0x09 */ NULL,
60 /* 0x0a */ NULL,
61 /* 0x0b */ NULL,
62 /* 0x0c */ "MIDI Reverb",
63 /* 0x0d */ "MIDI Chorus",
64 /* 0x0e */ NULL,
65 /* 0x0f */ NULL
66};
67
68static char *creative_ins[16] = {
69 /* 0x00 */ "AC97 Left",
70 /* 0x01 */ "AC97 Right",
71 /* 0x02 */ "TTL IEC958 Left",
72 /* 0x03 */ "TTL IEC958 Right",
73 /* 0x04 */ "Zoom Video Left",
74 /* 0x05 */ "Zoom Video Right",
75 /* 0x06 */ "Optical IEC958 Left",
76 /* 0x07 */ "Optical IEC958 Right",
77 /* 0x08 */ "Line/Mic 1 Left",
78 /* 0x09 */ "Line/Mic 1 Right",
79 /* 0x0a */ "Coaxial IEC958 Left",
80 /* 0x0b */ "Coaxial IEC958 Right",
81 /* 0x0c */ "Line/Mic 2 Left",
82 /* 0x0d */ "Line/Mic 2 Right",
83 /* 0x0e */ NULL,
84 /* 0x0f */ NULL
85};
86
87static char *audigy_ins[16] = {
88 /* 0x00 */ "AC97 Left",
89 /* 0x01 */ "AC97 Right",
90 /* 0x02 */ "Audigy CD Left",
91 /* 0x03 */ "Audigy CD Right",
92 /* 0x04 */ "Optical IEC958 Left",
93 /* 0x05 */ "Optical IEC958 Right",
94 /* 0x06 */ NULL,
95 /* 0x07 */ NULL,
96 /* 0x08 */ "Line/Mic 2 Left",
97 /* 0x09 */ "Line/Mic 2 Right",
98 /* 0x0a */ "SPDIF Left",
99 /* 0x0b */ "SPDIF Right",
100 /* 0x0c */ "Aux2 Left",
101 /* 0x0d */ "Aux2 Right",
102 /* 0x0e */ NULL,
103 /* 0x0f */ NULL
104};
105
106static char *creative_outs[32] = {
107 /* 0x00 */ "AC97 Left",
108 /* 0x01 */ "AC97 Right",
109 /* 0x02 */ "Optical IEC958 Left",
110 /* 0x03 */ "Optical IEC958 Right",
111 /* 0x04 */ "Center",
112 /* 0x05 */ "LFE",
113 /* 0x06 */ "Headphone Left",
114 /* 0x07 */ "Headphone Right",
115 /* 0x08 */ "Surround Left",
116 /* 0x09 */ "Surround Right",
117 /* 0x0a */ "PCM Capture Left",
118 /* 0x0b */ "PCM Capture Right",
119 /* 0x0c */ "MIC Capture",
120 /* 0x0d */ "AC97 Surround Left",
121 /* 0x0e */ "AC97 Surround Right",
122 /* 0x0f */ NULL,
123 /* 0x10 */ NULL,
124 /* 0x11 */ "Analog Center",
125 /* 0x12 */ "Analog LFE",
126 /* 0x13 */ NULL,
127 /* 0x14 */ NULL,
128 /* 0x15 */ NULL,
129 /* 0x16 */ NULL,
130 /* 0x17 */ NULL,
131 /* 0x18 */ NULL,
132 /* 0x19 */ NULL,
133 /* 0x1a */ NULL,
134 /* 0x1b */ NULL,
135 /* 0x1c */ NULL,
136 /* 0x1d */ NULL,
137 /* 0x1e */ NULL,
138 /* 0x1f */ NULL,
139};
140
141static char *audigy_outs[32] = {
142 /* 0x00 */ "Digital Front Left",
143 /* 0x01 */ "Digital Front Right",
144 /* 0x02 */ "Digital Center",
145 /* 0x03 */ "Digital LEF",
146 /* 0x04 */ "Headphone Left",
147 /* 0x05 */ "Headphone Right",
148 /* 0x06 */ "Digital Rear Left",
149 /* 0x07 */ "Digital Rear Right",
150 /* 0x08 */ "Front Left",
151 /* 0x09 */ "Front Right",
152 /* 0x0a */ "Center",
153 /* 0x0b */ "LFE",
154 /* 0x0c */ NULL,
155 /* 0x0d */ NULL,
156 /* 0x0e */ "Rear Left",
157 /* 0x0f */ "Rear Right",
158 /* 0x10 */ "AC97 Front Left",
159 /* 0x11 */ "AC97 Front Right",
Colin Ian Kingbf8b47f2018-05-17 09:04:20 +0100160 /* 0x12 */ "ADC Capture Left",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 /* 0x13 */ "ADC Capture Right",
162 /* 0x14 */ NULL,
163 /* 0x15 */ NULL,
164 /* 0x16 */ NULL,
165 /* 0x17 */ NULL,
166 /* 0x18 */ NULL,
167 /* 0x19 */ NULL,
168 /* 0x1a */ NULL,
169 /* 0x1b */ NULL,
170 /* 0x1c */ NULL,
171 /* 0x1d */ NULL,
172 /* 0x1e */ NULL,
173 /* 0x1f */ NULL,
174};
175
176static const u32 bass_table[41][5] = {
177 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
178 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
179 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
180 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
181 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
182 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
183 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
184 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
185 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
186 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
187 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
188 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
189 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
190 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
191 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
192 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
193 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
194 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
195 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
196 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
197 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
198 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
199 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
200 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
201 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
202 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
203 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
204 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
205 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
206 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
207 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
208 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
209 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
210 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
211 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
212 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
213 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
214 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
215 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
216 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
217 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
218};
219
220static const u32 treble_table[41][5] = {
221 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
222 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
223 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
224 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
225 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
226 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
227 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
228 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
229 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
230 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
231 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
232 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
233 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
234 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
235 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
236 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
237 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
238 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
239 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
240 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
241 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
242 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
243 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
244 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
245 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
246 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
247 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
248 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
249 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
250 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
251 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
252 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
253 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
254 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
255 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
256 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
257 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
258 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
259 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
260 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
261 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
262};
263
James Courtier-Dutton7012b2d2006-07-28 22:27:56 +0100264/* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static const u32 db_table[101] = {
266 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
267 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
268 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
269 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
270 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
271 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
272 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
273 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
274 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
275 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
276 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
277 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
278 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
279 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
280 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
281 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
282 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
283 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
284 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
285 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
286 0x7fffffff,
287};
288
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100289/* EMU10k1/EMU10k2 DSP control db gain */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100290static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
Clemens Ladisch4daf7a02010-05-25 09:04:49 +0200291static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100292
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +0800293/* EMU10K1 bass/treble db gain */
294static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296static const u32 onoff_table[2] = {
297 0x00000000, 0x00000001
298};
299
300/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 * controls
302 */
303
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100304static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100306 struct snd_emu10k1_fx8010_ctl *ctl =
307 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 if (ctl->min == 0 && ctl->max == 1)
310 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
311 else
312 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
313 uinfo->count = ctl->vcount;
314 uinfo->value.integer.min = ctl->min;
315 uinfo->value.integer.max = ctl->max;
316 return 0;
317}
318
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100319static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100321 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
322 struct snd_emu10k1_fx8010_ctl *ctl =
323 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 unsigned long flags;
325 unsigned int i;
326
327 spin_lock_irqsave(&emu->reg_lock, flags);
328 for (i = 0; i < ctl->vcount; i++)
329 ucontrol->value.integer.value[i] = ctl->value[i];
330 spin_unlock_irqrestore(&emu->reg_lock, flags);
331 return 0;
332}
333
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100334static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100336 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
337 struct snd_emu10k1_fx8010_ctl *ctl =
338 (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 unsigned long flags;
340 unsigned int nval, val;
341 unsigned int i, j;
342 int change = 0;
343
344 spin_lock_irqsave(&emu->reg_lock, flags);
345 for (i = 0; i < ctl->vcount; i++) {
346 nval = ucontrol->value.integer.value[i];
347 if (nval < ctl->min)
348 nval = ctl->min;
349 if (nval > ctl->max)
350 nval = ctl->max;
351 if (nval != ctl->value[i])
352 change = 1;
353 val = ctl->value[i] = nval;
354 switch (ctl->translation) {
355 case EMU10K1_GPR_TRANSLATION_NONE:
356 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
357 break;
358 case EMU10K1_GPR_TRANSLATION_TABLE100:
359 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
360 break;
361 case EMU10K1_GPR_TRANSLATION_BASS:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200362 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
363 change = -EIO;
364 goto __error;
365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 for (j = 0; j < 5; j++)
367 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
368 break;
369 case EMU10K1_GPR_TRANSLATION_TREBLE:
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200370 if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
371 change = -EIO;
372 goto __error;
373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 for (j = 0; j < 5; j++)
375 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
376 break;
377 case EMU10K1_GPR_TRANSLATION_ONOFF:
378 snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
379 break;
380 }
381 }
382 __error:
383 spin_unlock_irqrestore(&emu->reg_lock, flags);
384 return change;
385}
386
387/*
388 * Interrupt handler
389 */
390
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100391static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100393 struct snd_emu10k1_fx8010_irq *irq, *nirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
395 irq = emu->fx8010.irq_handlers;
396 while (irq) {
397 nirq = irq->next; /* irq ptr can be removed from list */
398 if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
399 if (irq->handler)
400 irq->handler(emu, irq->private_data);
401 snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
402 }
403 irq = nirq;
404 }
405}
406
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100407int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
408 snd_fx8010_irq_handler_t *handler,
409 unsigned char gpr_running,
410 void *private_data,
Takashi Iwai057666b2018-04-09 22:21:49 +0200411 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 unsigned long flags;
414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 irq->handler = handler;
416 irq->gpr_running = gpr_running;
417 irq->private_data = private_data;
418 irq->next = NULL;
419 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
420 if (emu->fx8010.irq_handlers == NULL) {
421 emu->fx8010.irq_handlers = irq;
422 emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
423 snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
424 } else {
425 irq->next = emu->fx8010.irq_handlers;
426 emu->fx8010.irq_handlers = irq;
427 }
428 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return 0;
430}
431
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100432int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
433 struct snd_emu10k1_fx8010_irq *irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100435 struct snd_emu10k1_fx8010_irq *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 unsigned long flags;
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
439 if ((tmp = emu->fx8010.irq_handlers) == irq) {
440 emu->fx8010.irq_handlers = tmp->next;
441 if (emu->fx8010.irq_handlers == NULL) {
442 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
443 emu->dsp_interrupt = NULL;
444 }
445 } else {
446 while (tmp && tmp->next != irq)
447 tmp = tmp->next;
448 if (tmp)
449 tmp->next = tmp->next->next;
450 }
451 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return 0;
453}
454
455/*************************************************************************
456 * EMU10K1 effect manager
457 *************************************************************************/
458
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100459static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
460 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 u32 op, u32 r, u32 a, u32 x, u32 y)
462{
463 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200464 if (snd_BUG_ON(*ptr >= 512))
465 return;
Clemens Ladisch4d233592005-09-05 10:35:20 +0200466 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 set_bit(*ptr, icode->code_valid);
468 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
469 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
470 (*ptr)++;
471}
472
473#define OP(icode, ptr, op, r, a, x, y) \
474 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
475
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100476static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
477 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 u32 op, u32 r, u32 a, u32 x, u32 y)
479{
480 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200481 if (snd_BUG_ON(*ptr >= 1024))
482 return;
Clemens Ladisch4d233592005-09-05 10:35:20 +0200483 code = (u_int32_t __force *)icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 set_bit(*ptr, icode->code_valid);
485 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
486 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
487 (*ptr)++;
488}
489
490#define A_OP(icode, ptr, op, r, a, x, y) \
491 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
492
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100493static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
495 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
496 snd_emu10k1_ptr_write(emu, pc, 0, data);
497}
498
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100499unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
502 return snd_emu10k1_ptr_read(emu, pc, 0);
503}
504
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100505static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200506 struct snd_emu10k1_fx8010_code *icode,
507 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 int gpr;
510 u32 val;
511
512 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
513 if (!test_bit(gpr, icode->gpr_valid))
514 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200515 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200516 val = *(__force u32 *)&icode->gpr_map[gpr];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200517 else if (get_user(val, &icode->gpr_map[gpr]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return -EFAULT;
519 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
520 }
521 return 0;
522}
523
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100524static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
525 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
527 int gpr;
528 u32 val;
529
530 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
531 set_bit(gpr, icode->gpr_valid);
532 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
533 if (put_user(val, &icode->gpr_map[gpr]))
534 return -EFAULT;
535 }
536 return 0;
537}
538
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100539static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200540 struct snd_emu10k1_fx8010_code *icode,
541 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 int tram;
544 u32 addr, val;
545
546 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
547 if (!test_bit(tram, icode->tram_valid))
548 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200549 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200550 val = *(__force u32 *)&icode->tram_data_map[tram];
551 addr = *(__force u32 *)&icode->tram_addr_map[tram];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200552 } else {
553 if (get_user(val, &icode->tram_data_map[tram]) ||
554 get_user(addr, &icode->tram_addr_map[tram]))
555 return -EFAULT;
556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
558 if (!emu->audigy) {
559 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
560 } else {
561 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
562 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
563 }
564 }
565 return 0;
566}
567
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100568static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
569 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 int tram;
572 u32 val, addr;
573
574 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
575 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
576 set_bit(tram, icode->tram_valid);
577 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
578 if (!emu->audigy) {
579 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
580 } else {
581 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
582 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
583 }
584 if (put_user(val, &icode->tram_data_map[tram]) ||
585 put_user(addr, &icode->tram_addr_map[tram]))
586 return -EFAULT;
587 }
588 return 0;
589}
590
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100591static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200592 struct snd_emu10k1_fx8010_code *icode,
593 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 u32 pc, lo, hi;
596
597 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
598 if (!test_bit(pc / 2, icode->code_valid))
599 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200600 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200601 lo = *(__force u32 *)&icode->code[pc + 0];
602 hi = *(__force u32 *)&icode->code[pc + 1];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200603 } else {
604 if (get_user(lo, &icode->code[pc + 0]) ||
605 get_user(hi, &icode->code[pc + 1]))
606 return -EFAULT;
607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 snd_emu10k1_efx_write(emu, pc + 0, lo);
609 snd_emu10k1_efx_write(emu, pc + 1, hi);
610 }
611 return 0;
612}
613
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100614static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
615 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616{
617 u32 pc;
618
619 memset(icode->code_valid, 0, sizeof(icode->code_valid));
620 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
621 set_bit(pc / 2, icode->code_valid);
622 if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0]))
623 return -EFAULT;
624 if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1]))
625 return -EFAULT;
626 }
627 return 0;
628}
629
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100630static struct snd_emu10k1_fx8010_ctl *
631snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100633 struct snd_emu10k1_fx8010_ctl *ctl;
634 struct snd_kcontrol *kcontrol;
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200635
636 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 kcontrol = ctl->kcontrol;
638 if (kcontrol->id.iface == id->iface &&
639 !strcmp(kcontrol->id.name, id->name) &&
640 kcontrol->id.index == id->index)
641 return ctl;
642 }
643 return NULL;
644}
645
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100646#define MAX_TLV_SIZE 256
647
Takashi Iwaid42fe632017-05-10 17:11:34 +0200648static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100649{
650 unsigned int data[2];
651 unsigned int *tlv;
652
653 if (!_tlv)
654 return NULL;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200655 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200656 memcpy(data, (__force void *)_tlv, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200657 else if (copy_from_user(data, _tlv, sizeof(data)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100658 return NULL;
659 if (data[1] >= MAX_TLV_SIZE)
660 return NULL;
Takashi Iwai6735e572008-01-19 10:33:07 +0100661 tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100662 if (!tlv)
663 return NULL;
664 memcpy(tlv, data, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200665 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200666 memcpy(tlv + 2, (__force void *)(_tlv + 2), data[1]);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200667 } else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100668 kfree(tlv);
669 return NULL;
670 }
671 return tlv;
672}
673
674static int copy_gctl(struct snd_emu10k1 *emu,
675 struct snd_emu10k1_fx8010_control_gpr *gctl,
676 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200677 int idx, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100678{
679 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
680
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200681 if (emu->support_tlv) {
682 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200683 memcpy(gctl, (__force void *)&_gctl[idx], sizeof(*gctl));
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200684 else if (copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)))
685 return -EFAULT;
686 return 0;
687 }
688
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100689 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200690 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200691 memcpy(gctl, (__force void *)&octl[idx], sizeof(*octl));
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200692 else if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100693 return -EFAULT;
694 gctl->tlv = NULL;
695 return 0;
696}
697
698static int copy_gctl_to_user(struct snd_emu10k1 *emu,
699 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
700 struct snd_emu10k1_fx8010_control_gpr *gctl,
701 int idx)
702{
703 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
704
705 if (emu->support_tlv)
706 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
707
708 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
709 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
710}
711
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100712static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200713 struct snd_emu10k1_fx8010_code *icode,
714 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100717 struct snd_ctl_elem_id __user *_id;
718 struct snd_ctl_elem_id id;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100719 struct snd_emu10k1_fx8010_control_gpr *gctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 int err;
721
722 for (i = 0, _id = icode->gpr_del_controls;
723 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200724 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200725 id = *(__force struct snd_ctl_elem_id *)_id;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200726 else if (copy_from_user(&id, _id, sizeof(id)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return -EFAULT;
728 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
729 return -ENOENT;
730 }
731 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
732 if (! gctl)
733 return -ENOMEM;
734 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100735 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200736 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
737 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 err = -EFAULT;
739 goto __error;
740 }
741 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
742 continue;
743 down_read(&emu->card->controls_rwsem);
744 if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) {
745 up_read(&emu->card->controls_rwsem);
746 err = -EEXIST;
747 goto __error;
748 }
749 up_read(&emu->card->controls_rwsem);
750 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
751 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
752 err = -EINVAL;
753 goto __error;
754 }
755 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100756 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 /* FIXME: we need to check the WRITE access */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200758 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i,
759 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 err = -EFAULT;
761 goto __error;
762 }
763 }
764 __error:
765 kfree(gctl);
766 return err;
767}
768
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100769static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100771 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100773 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 kctl->private_value = 0;
775 list_del(&ctl->list);
776 kfree(ctl);
Markus Elfring31604d32014-11-03 14:54:36 +0100777 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778}
779
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100780static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200781 struct snd_emu10k1_fx8010_code *icode,
782 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 unsigned int i, j;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100785 struct snd_emu10k1_fx8010_control_gpr *gctl;
786 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
787 struct snd_kcontrol_new knew;
788 struct snd_kcontrol *kctl;
789 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 int err = 0;
791
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100792 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
794 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
795 if (!val || !gctl || !nctl) {
796 err = -ENOMEM;
797 goto __error;
798 }
799
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100800 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200801 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
802 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 err = -EFAULT;
804 goto __error;
805 }
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200806 if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
807 gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) {
808 err = -EINVAL;
809 goto __error;
810 }
811 if (! gctl->id.name[0]) {
812 err = -EINVAL;
813 goto __error;
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
816 memset(&knew, 0, sizeof(knew));
817 knew.iface = gctl->id.iface;
818 knew.name = gctl->id.name;
819 knew.index = gctl->id.index;
820 knew.device = gctl->id.device;
821 knew.subdevice = gctl->id.subdevice;
822 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwai63623642018-07-25 23:00:57 +0200823 knew.tlv.p = copy_tlv((__force const unsigned int __user *)gctl->tlv, in_kernel);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100824 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100825 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
826 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 knew.get = snd_emu10k1_gpr_ctl_get;
828 knew.put = snd_emu10k1_gpr_ctl_put;
829 memset(nctl, 0, sizeof(*nctl));
830 nctl->vcount = gctl->vcount;
831 nctl->count = gctl->count;
832 for (j = 0; j < 32; j++) {
833 nctl->gpr[j] = gctl->gpr[j];
834 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
835 val->value.integer.value[j] = gctl->value[j];
836 }
837 nctl->min = gctl->min;
838 nctl->max = gctl->max;
839 nctl->translation = gctl->translation;
840 if (ctl == NULL) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100841 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (ctl == NULL) {
843 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100844 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 goto __error;
846 }
847 knew.private_value = (unsigned long)ctl;
848 *ctl = *nctl;
849 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
850 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100851 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 goto __error;
853 }
854 kctl->private_free = snd_emu10k1_ctl_private_free;
855 ctl->kcontrol = kctl;
856 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
857 } else {
858 /* overwrite */
859 nctl->list = ctl->list;
860 nctl->kcontrol = ctl->kcontrol;
861 *ctl = *nctl;
862 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
863 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
864 }
865 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
866 }
867 __error:
868 kfree(nctl);
869 kfree(gctl);
870 kfree(val);
871 return err;
872}
873
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100874static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200875 struct snd_emu10k1_fx8010_code *icode,
876 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 unsigned int i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100879 struct snd_ctl_elem_id id;
880 struct snd_ctl_elem_id __user *_id;
881 struct snd_emu10k1_fx8010_ctl *ctl;
882 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 for (i = 0, _id = icode->gpr_del_controls;
885 i < icode->gpr_del_control_count; i++, _id++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200886 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200887 id = *(__force struct snd_ctl_elem_id *)_id;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200888 else if (copy_from_user(&id, _id, sizeof(id)))
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200889 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 down_write(&card->controls_rwsem);
891 ctl = snd_emu10k1_look_for_ctl(emu, &id);
892 if (ctl)
893 snd_ctl_remove(card, ctl->kcontrol);
894 up_write(&card->controls_rwsem);
895 }
896 return 0;
897}
898
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100899static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
900 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 unsigned int i = 0, j;
903 unsigned int total = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100904 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100905 struct snd_emu10k1_fx8010_ctl *ctl;
906 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
908 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
909 if (! gctl)
910 return -ENOMEM;
911
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200912 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100914 if (icode->gpr_list_controls &&
915 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 memset(gctl, 0, sizeof(*gctl));
917 id = &ctl->kcontrol->id;
918 gctl->id.iface = id->iface;
919 strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name));
920 gctl->id.index = id->index;
921 gctl->id.device = id->device;
922 gctl->id.subdevice = id->subdevice;
923 gctl->vcount = ctl->vcount;
924 gctl->count = ctl->count;
925 for (j = 0; j < 32; j++) {
926 gctl->gpr[j] = ctl->gpr[j];
927 gctl->value[j] = ctl->value[j];
928 }
929 gctl->min = ctl->min;
930 gctl->max = ctl->max;
931 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100932 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
933 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 kfree(gctl);
935 return -EFAULT;
936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 i++;
938 }
939 }
940 icode->gpr_list_control_total = total;
941 kfree(gctl);
942 return 0;
943}
944
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100945static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200946 struct snd_emu10k1_fx8010_code *icode,
947 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 int err = 0;
950
Ingo Molnar62932df2006-01-16 16:34:20 +0100951 mutex_lock(&emu->fx8010.lock);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200952 err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
953 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 goto __error;
955 strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
956 /* stop FX processor - this may be dangerous, but it's better to miss
957 some samples than generate wrong ones - [jk] */
958 if (emu->audigy)
959 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
960 else
961 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
962 /* ok, do the main job */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200963 err = snd_emu10k1_del_controls(emu, icode, in_kernel);
964 if (err < 0)
965 goto __error;
966 err = snd_emu10k1_gpr_poke(emu, icode, in_kernel);
967 if (err < 0)
968 goto __error;
969 err = snd_emu10k1_tram_poke(emu, icode, in_kernel);
970 if (err < 0)
971 goto __error;
972 err = snd_emu10k1_code_poke(emu, icode, in_kernel);
973 if (err < 0)
974 goto __error;
975 err = snd_emu10k1_add_controls(emu, icode, in_kernel);
976 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 goto __error;
978 /* start FX processor when the DSP code is updated */
979 if (emu->audigy)
980 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
981 else
982 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
983 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +0100984 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 return err;
986}
987
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100988static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
989 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int err;
992
Ingo Molnar62932df2006-01-16 16:34:20 +0100993 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
995 /* ok, do the main job */
996 err = snd_emu10k1_gpr_peek(emu, icode);
997 if (err >= 0)
998 err = snd_emu10k1_tram_peek(emu, icode);
999 if (err >= 0)
1000 err = snd_emu10k1_code_peek(emu, icode);
1001 if (err >= 0)
1002 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +01001003 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 return err;
1005}
1006
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001007static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
1008 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
1010 unsigned int i;
1011 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001012 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1015 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001016 ipcm->substream = array_index_nospec(ipcm->substream,
1017 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 if (ipcm->channels > 32)
1019 return -EINVAL;
1020 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001021 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 spin_lock_irq(&emu->reg_lock);
1023 if (pcm->opened) {
1024 err = -EBUSY;
1025 goto __error;
1026 }
1027 if (ipcm->channels == 0) { /* remove */
1028 pcm->valid = 0;
1029 } else {
1030 /* FIXME: we need to add universal code to the PCM transfer routine */
1031 if (ipcm->channels != 2) {
1032 err = -EINVAL;
1033 goto __error;
1034 }
1035 pcm->valid = 1;
1036 pcm->opened = 0;
1037 pcm->channels = ipcm->channels;
1038 pcm->tram_start = ipcm->tram_start;
1039 pcm->buffer_size = ipcm->buffer_size;
1040 pcm->gpr_size = ipcm->gpr_size;
1041 pcm->gpr_count = ipcm->gpr_count;
1042 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1043 pcm->gpr_ptr = ipcm->gpr_ptr;
1044 pcm->gpr_trigger = ipcm->gpr_trigger;
1045 pcm->gpr_running = ipcm->gpr_running;
1046 for (i = 0; i < pcm->channels; i++)
1047 pcm->etram[i] = ipcm->etram[i];
1048 }
1049 __error:
1050 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001051 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return err;
1053}
1054
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001055static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1056 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
1058 unsigned int i;
1059 int err = 0;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001060 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
1062 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1063 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001064 ipcm->substream = array_index_nospec(ipcm->substream,
1065 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001067 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 spin_lock_irq(&emu->reg_lock);
1069 ipcm->channels = pcm->channels;
1070 ipcm->tram_start = pcm->tram_start;
1071 ipcm->buffer_size = pcm->buffer_size;
1072 ipcm->gpr_size = pcm->gpr_size;
1073 ipcm->gpr_ptr = pcm->gpr_ptr;
1074 ipcm->gpr_count = pcm->gpr_count;
1075 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1076 ipcm->gpr_trigger = pcm->gpr_trigger;
1077 ipcm->gpr_running = pcm->gpr_running;
1078 for (i = 0; i < pcm->channels; i++)
1079 ipcm->etram[i] = pcm->etram[i];
1080 ipcm->res1 = ipcm->res2 = 0;
1081 ipcm->pad = 0;
1082 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001083 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return err;
1085}
1086
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001087#define SND_EMU10K1_GPR_CONTROLS 44
1088#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1090#define SND_EMU10K1_CAPTURE_CHANNELS 4
1091
Bill Pembertone23e7a12012-12-06 12:35:10 -05001092static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001093snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1094 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
1096 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1097 strcpy(ctl->id.name, name);
1098 ctl->vcount = ctl->count = 1;
1099 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001100 if (high_res_gpr_volume) {
1101 ctl->min = 0;
1102 ctl->max = 0x7fffffff;
1103 ctl->tlv = snd_emu10k1_db_linear;
1104 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1105 } else {
1106 ctl->min = 0;
1107 ctl->max = 100;
1108 ctl->tlv = snd_emu10k1_db_scale1;
1109 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111}
1112
Bill Pembertone23e7a12012-12-06 12:35:10 -05001113static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001114snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1115 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
1117 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1118 strcpy(ctl->id.name, name);
1119 ctl->vcount = ctl->count = 2;
1120 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1121 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001122 if (high_res_gpr_volume) {
1123 ctl->min = 0;
1124 ctl->max = 0x7fffffff;
1125 ctl->tlv = snd_emu10k1_db_linear;
1126 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1127 } else {
1128 ctl->min = 0;
1129 ctl->max = 100;
1130 ctl->tlv = snd_emu10k1_db_scale1;
1131 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
1134
Bill Pembertone23e7a12012-12-06 12:35:10 -05001135static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001136snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1137 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
1139 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1140 strcpy(ctl->id.name, name);
1141 ctl->vcount = ctl->count = 1;
1142 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1143 ctl->min = 0;
1144 ctl->max = 1;
1145 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1146}
1147
Bill Pembertone23e7a12012-12-06 12:35:10 -05001148static void
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001149snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1150 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151{
1152 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1153 strcpy(ctl->id.name, name);
1154 ctl->vcount = ctl->count = 2;
1155 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1156 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1157 ctl->min = 0;
1158 ctl->max = 1;
1159 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1160}
1161
Pavel Hofman13d45702007-06-11 12:21:20 +02001162/*
1163 * Used for emu1010 - conversion from 32-bit capture inputs from HANA
1164 * to 2 x 16-bit registers in audigy - their values are read via DMA.
1165 * Conversion is performed by Audigy DSP instructions of FX8010.
1166 */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001167static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1168 struct snd_emu10k1_fx8010_code *icode,
1169 u32 *ptr, int tmp, int bit_shifter16,
1170 int reg_in, int reg_out)
1171{
1172 A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
1173 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
1174 A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
1175 A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
1176 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
1177 A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
1178 A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
1179 A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
1180 return 1;
1181}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183/*
1184 * initial DSP configuration for Audigy
1185 */
1186
Bill Pembertone23e7a12012-12-06 12:35:10 -05001187static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188{
1189 int err, i, z, gpr, nctl;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001190 int bit_shifter16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 const int playback = 10;
1192 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1193 const int stereo_mix = capture + 2;
1194 const int tmp = 0x88;
1195 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001196 struct snd_emu10k1_fx8010_code *icode = NULL;
1197 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001200 err = -ENOMEM;
1201 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1202 if (!icode)
1203 return err;
1204
1205 icode->gpr_map = (u_int32_t __user *) kcalloc(512 + 256 + 256 + 2 * 1024,
1206 sizeof(u_int32_t), GFP_KERNEL);
1207 if (!icode->gpr_map)
1208 goto __err_gpr;
1209 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1210 sizeof(*controls), GFP_KERNEL);
1211 if (!controls)
1212 goto __err_ctrls;
1213
Clemens Ladisch4d233592005-09-05 10:35:20 +02001214 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
1216 icode->tram_data_map = icode->gpr_map + 512;
1217 icode->tram_addr_map = icode->tram_data_map + 256;
1218 icode->code = icode->tram_addr_map + 256;
1219
1220 /* clear free GPRs */
1221 for (i = 0; i < 512; i++)
1222 set_bit(i, icode->gpr_valid);
1223
1224 /* clear TRAM data & address lines */
1225 for (i = 0; i < 256; i++)
1226 set_bit(i, icode->tram_valid);
1227
1228 strcpy(icode->name, "Audigy DSP code for ALSA");
1229 ptr = 0;
1230 nctl = 0;
1231 gpr = stereo_mix + 10;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001232 gpr_map[gpr++] = 0x00007fff;
1233 gpr_map[gpr++] = 0x00008000;
1234 gpr_map[gpr++] = 0x0000ffff;
1235 bit_shifter16 = gpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 /* stop FX processor */
1238 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1239
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001240#if 1
Pavel Hofman13d45702007-06-11 12:21:20 +02001241 /* PCM front Playback Volume (independent from stereo mix)
1242 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
1243 * where gpr contains attenuation from corresponding mixer control
1244 * (snd_emu10k1_init_stereo_control)
1245 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1247 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1248 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1249 gpr += 2;
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001250
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 /* PCM Surround Playback (independent from stereo mix) */
1252 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1253 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1254 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1255 gpr += 2;
1256
1257 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001258 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1260 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1261 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1262 gpr += 2;
1263 }
1264
1265 /* PCM Center Playback (independent from stereo mix) */
1266 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1267 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1268 gpr++;
1269
1270 /* PCM LFE Playback (independent from stereo mix) */
1271 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1272 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1273 gpr++;
1274
1275 /*
1276 * Stereo Mix
1277 */
1278 /* Wave (PCM) Playback Volume (will be renamed later) */
1279 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1280 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1281 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1282 gpr += 2;
1283
1284 /* Synth Playback */
1285 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1286 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1287 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1288 gpr += 2;
1289
1290 /* Wave (PCM) Capture */
1291 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1292 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1293 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1294 gpr += 2;
1295
1296 /* Synth Capture */
1297 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1298 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1299 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1300 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001301
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 /*
1303 * inputs
1304 */
1305#define A_ADD_VOLUME_IN(var,vol,input) \
1306A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1307
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001308 /* emu1212 DSP 0 and DSP 1 Capture */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001309 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001310 if (emu->card_capabilities->ca0108_chip) {
1311 /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
1312 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
1313 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
1314 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
1315 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
1316 } else {
1317 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1318 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1319 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001320 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1321 gpr += 2;
1322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 /* AC'97 Playback Volume - used only for mic (renamed later) */
1324 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1325 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1326 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1327 gpr += 2;
1328 /* AC'97 Capture Volume - used only for mic */
1329 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1330 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1331 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1332 gpr += 2;
1333
1334 /* mic capture buffer */
1335 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1336
1337 /* Audigy CD Playback Volume */
1338 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1339 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1340 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001341 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 gpr, 0);
1343 gpr += 2;
1344 /* Audigy CD Capture Volume */
1345 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1346 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1347 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001348 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 gpr, 0);
1350 gpr += 2;
1351
1352 /* Optical SPDIF Playback Volume */
1353 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1354 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001355 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 gpr += 2;
1357 /* Optical SPDIF Capture Volume */
1358 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1359 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001360 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 gpr += 2;
1362
1363 /* Line2 Playback Volume */
1364 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1365 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1366 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001367 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 gpr, 0);
1369 gpr += 2;
1370 /* Line2 Capture Volume */
1371 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1372 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1373 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001374 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 gpr, 0);
1376 gpr += 2;
1377
1378 /* Philips ADC Playback Volume */
1379 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1380 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1381 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1382 gpr += 2;
1383 /* Philips ADC Capture Volume */
1384 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1385 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1386 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1387 gpr += 2;
1388
1389 /* Aux2 Playback Volume */
1390 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1391 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1392 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001393 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 gpr, 0);
1395 gpr += 2;
1396 /* Aux2 Capture Volume */
1397 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1398 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1399 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001400 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 gpr, 0);
1402 gpr += 2;
1403
1404 /* Stereo Mix Front Playback Volume */
1405 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1406 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1407 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1408 gpr += 2;
1409
1410 /* Stereo Mix Surround Playback */
1411 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1412 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1413 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1414 gpr += 2;
1415
1416 /* Stereo Mix Center Playback */
1417 /* Center = sub = Left/2 + Right/2 */
1418 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1419 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1420 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1421 gpr++;
1422
1423 /* Stereo Mix LFE Playback */
1424 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1425 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1426 gpr++;
1427
Lee Revell2b637da2005-03-30 13:51:18 +02001428 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 /* Stereo Mix Side Playback */
1430 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1431 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1432 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1433 gpr += 2;
1434 }
1435
1436 /*
1437 * outputs
1438 */
1439#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1440#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1441 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1442
1443#define _A_SWITCH(icode, ptr, dst, src, sw) \
1444 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1445#define A_SWITCH(icode, ptr, dst, src, sw) \
1446 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1447#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1448 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1449#define A_SWITCH_NEG(icode, ptr, dst, src) \
1450 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1451
1452
1453 /*
1454 * Process tone control
1455 */
1456 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1457 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1458 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 */
1459 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 */
1460 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1461 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 +02001462 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 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 */
1464 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 */
1465 }
1466
1467
1468 ctl = &controls[nctl + 0];
1469 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1470 strcpy(ctl->id.name, "Tone Control - Bass");
1471 ctl->vcount = 2;
1472 ctl->count = 10;
1473 ctl->min = 0;
1474 ctl->max = 40;
1475 ctl->value[0] = ctl->value[1] = 20;
1476 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1477 ctl = &controls[nctl + 1];
1478 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1479 strcpy(ctl->id.name, "Tone Control - Treble");
1480 ctl->vcount = 2;
1481 ctl->count = 10;
1482 ctl->min = 0;
1483 ctl->max = 40;
1484 ctl->value[0] = ctl->value[1] = 20;
1485 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1486
1487#define BASS_GPR 0x8c
1488#define TREBLE_GPR 0x96
1489
1490 for (z = 0; z < 5; z++) {
1491 int j;
1492 for (j = 0; j < 2; j++) {
1493 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1494 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1495 }
1496 }
1497 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1498 int j, k, l, d;
1499 for (j = 0; j < 2; j++) { /* left/right */
1500 k = 0xb0 + (z * 8) + (j * 4);
1501 l = 0xe0 + (z * 8) + (j * 4);
1502 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1503
1504 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1505 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1506 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1507 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1508 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1509 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1510
1511 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1512 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1513 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1514 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1515 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1516 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1517
1518 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1519
1520 if (z == 2) /* center */
1521 break;
1522 }
1523 }
1524 nctl += 2;
1525
1526#undef BASS_GPR
1527#undef TREBLE_GPR
1528
1529 for (z = 0; z < 8; z++) {
1530 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1531 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1532 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1533 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1534 }
1535 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1536 gpr += 2;
1537
1538 /* Master volume (will be renamed later) */
1539 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));
1540 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));
1541 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));
1542 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));
1543 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));
1544 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));
1545 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));
1546 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));
1547 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1548 gpr += 2;
1549
1550 /* analog speakers */
1551 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1552 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1553 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1554 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001555 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1557
1558 /* headphone */
1559 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1560
1561 /* digital outputs */
1562 /* 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 +00001563 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001564 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
Takashi Iwai6f002b02014-02-25 17:02:09 +01001565 dev_info(emu->card->dev, "EMU outputs on\n");
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001566 for (z = 0; z < 8; z++) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001567 if (emu->card_capabilities->ca0108_chip) {
1568 A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1569 } else {
1570 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1571 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001572 }
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 /* IEC958 Optical Raw Playback Switch */
1576 gpr_map[gpr++] = 0;
1577 gpr_map[gpr++] = 0x1008;
1578 gpr_map[gpr++] = 0xffff0000;
1579 for (z = 0; z < 2; z++) {
1580 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1581 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1582 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1583 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1584 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1585 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1586 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1587 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1588 /* 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 +01001589 dev_info(emu->card->dev,
1590 "Installing spdif_bug patch: %s\n",
1591 emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1593 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1594 } else {
1595 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1596 }
1597 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001598 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 -07001599 gpr += 2;
1600
1601 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1602 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1603 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1604
1605 /* ADC buffer */
1606#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1607 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1608#else
1609 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1610 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1611#endif
1612
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001613 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001614 if (emu->card_capabilities->ca0108_chip) {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001615 dev_info(emu->card->dev, "EMU2 inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001616 for (z = 0; z < 0x10; z++) {
1617 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
1618 bit_shifter16,
1619 A3_EMU32IN(z),
1620 A_FXBUS2(z*2) );
1621 }
1622 } else {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001623 dev_info(emu->card->dev, "EMU inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001624 /* Capture 16 (originally 8) channels of S32_LE sound */
1625
Takashi Iwai28a97c12009-02-05 16:08:14 +01001626 /*
Takashi Iwai6f002b02014-02-25 17:02:09 +01001627 dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
Takashi Iwai28a97c12009-02-05 16:08:14 +01001628 gpr, tmp);
1629 */
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001630 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1631 /* A_P16VIN(0) is delayed by one sample,
1632 * so all other A_P16VIN channels will need to also be delayed
1633 */
1634 /* Left ADC in. 1 of 2 */
1635 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1636 /* Right ADC in 1 of 2 */
1637 gpr_map[gpr++] = 0x00000000;
1638 /* Delaying by one sample: instead of copying the input
1639 * value A_P16VIN to output A_FXBUS2 as in the first channel,
1640 * we use an auxiliary register, delaying the value by one
1641 * sample
1642 */
1643 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1644 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1645 gpr_map[gpr++] = 0x00000000;
1646 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1647 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
1648 gpr_map[gpr++] = 0x00000000;
1649 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
1650 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1651 /* For 96kHz mode */
1652 /* Left ADC in. 2 of 2 */
1653 gpr_map[gpr++] = 0x00000000;
1654 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1655 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1656 /* Right ADC in 2 of 2 */
1657 gpr_map[gpr++] = 0x00000000;
1658 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1659 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
1660 gpr_map[gpr++] = 0x00000000;
1661 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
1662 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
1663 gpr_map[gpr++] = 0x00000000;
1664 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
1665 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1666 /* Pavel Hofman - we still have voices, A_FXBUS2s, and
1667 * A_P16VINs available -
1668 * let's add 8 more capture channels - total of 16
1669 */
1670 gpr_map[gpr++] = 0x00000000;
1671 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1672 bit_shifter16,
1673 A_GPR(gpr - 1),
1674 A_FXBUS2(0x10));
1675 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
1676 A_C_00000000, A_C_00000000);
1677 gpr_map[gpr++] = 0x00000000;
1678 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1679 bit_shifter16,
1680 A_GPR(gpr - 1),
1681 A_FXBUS2(0x12));
1682 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
1683 A_C_00000000, A_C_00000000);
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(0x14));
1689 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
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(0x16));
1696 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
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(0x18));
1703 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
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(0x1a));
1710 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
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(0x1c));
1717 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
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(0x1e));
1724 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
1725 A_C_00000000, A_C_00000000);
1726 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001727
1728#if 0
1729 for (z = 4; z < 8; z++) {
1730 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1731 }
1732 for (z = 0xc; z < 0x10; z++) {
1733 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1734 }
1735#endif
1736 } else {
1737 /* EFX capture - capture the 16 EXTINs */
1738 /* Capture 16 channels of S16_LE sound */
1739 for (z = 0; z < 16; z++) {
1740 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001744#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 /*
1746 * ok, set up done..
1747 */
1748
1749 if (gpr > tmp) {
1750 snd_BUG();
1751 err = -EIO;
1752 goto __err;
1753 }
1754 /* clear remaining instruction memory */
1755 while (ptr < 0x400)
1756 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 icode->gpr_add_control_count = nctl;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001759 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001760 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02001761 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001762 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001764__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001766__err_ctrls:
1767 kfree((void __force *)icode->gpr_map);
1768__err_gpr:
1769 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 return err;
1771}
1772
1773
1774/*
1775 * initial DSP configuration for Emu10k1
1776 */
1777
1778/* when volume = max, then copy only to avoid volume modification */
1779/* with iMAC0 (negative values) */
Bill Pembertone23e7a12012-12-06 12:35:10 -05001780static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781{
1782 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1783 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1784 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1785 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1786}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001787static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788{
1789 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1790 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1791 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1792 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1793 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1794}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001795static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
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_00000002);
1799 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1800 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1801 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1802}
1803
1804#define VOLUME(icode, ptr, dst, src, vol) \
1805 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1806#define VOLUME_IN(icode, ptr, dst, src, vol) \
1807 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1808#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1809 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1810#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1811 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1812#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1813 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1814#define _SWITCH(icode, ptr, dst, src, sw) \
1815 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1816#define SWITCH(icode, ptr, dst, src, sw) \
1817 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1818#define SWITCH_IN(icode, ptr, dst, src, sw) \
1819 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1820#define _SWITCH_NEG(icode, ptr, dst, src) \
1821 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1822#define SWITCH_NEG(icode, ptr, dst, src) \
1823 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1824
1825
Bill Pembertone23e7a12012-12-06 12:35:10 -05001826static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827{
1828 int err, i, z, gpr, tmp, playback, capture;
1829 u32 ptr;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01001830 struct snd_emu10k1_fx8010_code *icode;
1831 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1832 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001835 err = -ENOMEM;
1836 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1837 if (!icode)
1838 return err;
1839
1840 icode->gpr_map = (u_int32_t __user *) kcalloc(256 + 160 + 160 + 2 * 512,
1841 sizeof(u_int32_t), GFP_KERNEL);
1842 if (!icode->gpr_map)
1843 goto __err_gpr;
1844
1845 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1846 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1847 GFP_KERNEL);
1848 if (!controls)
1849 goto __err_ctrls;
1850
1851 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
1852 if (!ipcm)
1853 goto __err_ipcm;
1854
Clemens Ladisch4d233592005-09-05 10:35:20 +02001855 gpr_map = (u32 __force *)icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856
1857 icode->tram_data_map = icode->gpr_map + 256;
1858 icode->tram_addr_map = icode->tram_data_map + 160;
1859 icode->code = icode->tram_addr_map + 160;
1860
1861 /* clear free GPRs */
1862 for (i = 0; i < 256; i++)
1863 set_bit(i, icode->gpr_valid);
1864
1865 /* clear TRAM data & address lines */
1866 for (i = 0; i < 160; i++)
1867 set_bit(i, icode->tram_valid);
1868
1869 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1870 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001871 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 playback = SND_EMU10K1_INPUTS;
1873 /* we have 6 playback channels and tone control doubles */
1874 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1875 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1876 tmp = 0x88; /* we need 4 temporary GPR */
1877 /* from 0x8c to 0xff is the area for tone control */
1878
1879 /* stop FX processor */
1880 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1881
1882 /*
1883 * Process FX Buses
1884 */
1885 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1886 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1887 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1888 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1889 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1890 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1891 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1892 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1893 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1894 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001895 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1896 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897
1898 /* Raw S/PDIF PCM */
1899 ipcm->substream = 0;
1900 ipcm->channels = 2;
1901 ipcm->tram_start = 0;
1902 ipcm->buffer_size = (64 * 1024) / 2;
1903 ipcm->gpr_size = gpr++;
1904 ipcm->gpr_ptr = gpr++;
1905 ipcm->gpr_count = gpr++;
1906 ipcm->gpr_tmpcount = gpr++;
1907 ipcm->gpr_trigger = gpr++;
1908 ipcm->gpr_running = gpr++;
1909 ipcm->etram[0] = 0;
1910 ipcm->etram[1] = 1;
1911
1912 gpr_map[gpr + 0] = 0xfffff000;
1913 gpr_map[gpr + 1] = 0xffff0000;
1914 gpr_map[gpr + 2] = 0x70000000;
1915 gpr_map[gpr + 3] = 0x00000007;
1916 gpr_map[gpr + 4] = 0x001f << 11;
1917 gpr_map[gpr + 5] = 0x001c << 11;
1918 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1919 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1920 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1921 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1922 gpr_map[gpr + 10] = 1<<11;
1923 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1924 gpr_map[gpr + 12] = 0;
1925
1926 /* if the trigger flag is not set, skip */
1927 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1928 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1929 /* if the running flag is set, we're running */
1930 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1931 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1932 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1933 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1934 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1935 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1936 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1937
1938 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1939 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1940 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1941 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1942
1943 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1944 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1945 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1946 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1947 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1948
1949 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1950 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1951 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1952 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1953 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1954
1955 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1956 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1957 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1958 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1959 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1960
1961 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1962 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1963 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1964 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1965 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1966
1967 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1968 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1969
1970 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1971 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1972
1973 /* 24: */
1974 gpr += 13;
1975
1976 /* Wave Playback Volume */
1977 for (z = 0; z < 2; z++)
1978 VOLUME(icode, &ptr, playback + z, z, gpr + z);
1979 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
1980 gpr += 2;
1981
1982 /* Wave Surround Playback Volume */
1983 for (z = 0; z < 2; z++)
1984 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
1985 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
1986 gpr += 2;
1987
1988 /* Wave Center/LFE Playback Volume */
1989 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1990 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
1991 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
1992 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
1993 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
1994 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
1995
1996 /* Wave Capture Volume + Switch */
1997 for (z = 0; z < 2; z++) {
1998 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
1999 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
2000 }
2001 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
2002 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
2003 gpr += 4;
2004
2005 /* Synth Playback Volume */
2006 for (z = 0; z < 2; z++)
2007 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
2008 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
2009 gpr += 2;
2010
2011 /* Synth Capture Volume + Switch */
2012 for (z = 0; z < 2; z++) {
2013 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
2014 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2015 }
2016 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
2017 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
2018 gpr += 4;
2019
2020 /* Surround Digital Playback Volume (renamed later without Digital) */
2021 for (z = 0; z < 2; z++)
2022 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
2023 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
2024 gpr += 2;
2025
2026 /* Surround Capture Volume + Switch */
2027 for (z = 0; z < 2; z++) {
2028 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
2029 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2030 }
2031 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
2032 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
2033 gpr += 4;
2034
2035 /* Center Playback Volume (renamed later without Digital) */
2036 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
2037 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
2038
2039 /* LFE Playback Volume + Switch (renamed later without Digital) */
2040 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
2041 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
2042
Mikael Magnussonedf8e452005-09-13 11:32:58 +02002043 /* Front Playback Volume */
2044 for (z = 0; z < 2; z++)
2045 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
2046 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
2047 gpr += 2;
2048
2049 /* Front Capture Volume + Switch */
2050 for (z = 0; z < 2; z++) {
2051 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
2052 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2053 }
2054 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2055 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2056 gpr += 3;
2057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 /*
2059 * Process inputs
2060 */
2061
2062 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
2063 /* AC'97 Playback Volume */
2064 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
2065 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
2066 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
2067 /* AC'97 Capture Volume */
2068 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
2069 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
2070 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
2071 }
2072
2073 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
2074 /* IEC958 TTL Playback Volume */
2075 for (z = 0; z < 2; z++)
2076 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002077 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 gpr += 2;
2079
2080 /* IEC958 TTL Capture Volume + Switch */
2081 for (z = 0; z < 2; z++) {
2082 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
2083 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2084 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002085 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
2086 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 -07002087 gpr += 4;
2088 }
2089
2090 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
2091 /* Zoom Video Playback Volume */
2092 for (z = 0; z < 2; z++)
2093 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
2094 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
2095 gpr += 2;
2096
2097 /* Zoom Video Capture Volume + Switch */
2098 for (z = 0; z < 2; z++) {
2099 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
2100 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2101 }
2102 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
2103 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
2104 gpr += 4;
2105 }
2106
2107 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
2108 /* IEC958 Optical Playback Volume */
2109 for (z = 0; z < 2; z++)
2110 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002111 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 gpr += 2;
2113
2114 /* IEC958 Optical Capture Volume */
2115 for (z = 0; z < 2; z++) {
2116 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
2117 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2118 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002119 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
2120 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 -07002121 gpr += 4;
2122 }
2123
2124 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
2125 /* Line LiveDrive Playback Volume */
2126 for (z = 0; z < 2; z++)
2127 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
2128 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
2129 gpr += 2;
2130
2131 /* Line LiveDrive Capture Volume + Switch */
2132 for (z = 0; z < 2; z++) {
2133 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
2134 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2135 }
2136 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
2137 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
2138 gpr += 4;
2139 }
2140
2141 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
2142 /* IEC958 Coax Playback Volume */
2143 for (z = 0; z < 2; z++)
2144 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002145 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 gpr += 2;
2147
2148 /* IEC958 Coax Capture Volume + Switch */
2149 for (z = 0; z < 2; z++) {
2150 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2151 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2152 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002153 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2154 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 -07002155 gpr += 4;
2156 }
2157
2158 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2159 /* Line LiveDrive Playback Volume */
2160 for (z = 0; z < 2; z++)
2161 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2162 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2163 controls[i-1].id.index = 1;
2164 gpr += 2;
2165
2166 /* Line LiveDrive Capture Volume */
2167 for (z = 0; z < 2; z++) {
2168 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2169 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2170 }
2171 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2172 controls[i-1].id.index = 1;
2173 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2174 controls[i-1].id.index = 1;
2175 gpr += 4;
2176 }
2177
2178 /*
2179 * Process tone control
2180 */
2181 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2182 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2183 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2184 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2185 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2186 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2187
2188 ctl = &controls[i + 0];
2189 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2190 strcpy(ctl->id.name, "Tone Control - Bass");
2191 ctl->vcount = 2;
2192 ctl->count = 10;
2193 ctl->min = 0;
2194 ctl->max = 40;
2195 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002196 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2198 ctl = &controls[i + 1];
2199 ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2200 strcpy(ctl->id.name, "Tone Control - Treble");
2201 ctl->vcount = 2;
2202 ctl->count = 10;
2203 ctl->min = 0;
2204 ctl->max = 40;
2205 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002206 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2208
2209#define BASS_GPR 0x8c
2210#define TREBLE_GPR 0x96
2211
2212 for (z = 0; z < 5; z++) {
2213 int j;
2214 for (j = 0; j < 2; j++) {
2215 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2216 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2217 }
2218 }
2219 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2220 int j, k, l, d;
2221 for (j = 0; j < 2; j++) { /* left/right */
2222 k = 0xa0 + (z * 8) + (j * 4);
2223 l = 0xd0 + (z * 8) + (j * 4);
2224 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2225
2226 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2227 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2228 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2229 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2230 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2231 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2232
2233 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2234 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2235 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2236 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2237 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2238 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2239
2240 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2241
2242 if (z == 2) /* center */
2243 break;
2244 }
2245 }
2246 i += 2;
2247
2248#undef BASS_GPR
2249#undef TREBLE_GPR
2250
2251 for (z = 0; z < 6; z++) {
2252 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2253 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2254 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2255 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2256 }
2257 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2258 gpr += 2;
2259
2260 /*
2261 * Process outputs
2262 */
2263 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2264 /* AC'97 Playback Volume */
2265
2266 for (z = 0; z < 2; z++)
2267 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2268 }
2269
2270 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2271 /* IEC958 Optical Raw Playback Switch */
2272
2273 for (z = 0; z < 2; z++) {
2274 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2275 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2276 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2277 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2278#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2279 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2280#endif
2281 }
2282
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002283 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 -07002284 gpr += 2;
2285 }
2286
2287 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2288 /* Headphone Playback Volume */
2289
2290 for (z = 0; z < 2; z++) {
2291 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2292 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2293 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2294 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2295 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2296 }
2297
2298 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2299 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2300 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2301 controls[i-1].id.index = 1;
2302 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2303 controls[i-1].id.index = 1;
2304
2305 gpr += 4;
2306 }
2307
2308 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2309 for (z = 0; z < 2; z++)
2310 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2311
2312 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2313 for (z = 0; z < 2; z++)
2314 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2315
2316 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2317#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2318 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2319 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2320#else
2321 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2322 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2323#endif
2324 }
2325
2326 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2327#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2328 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2329 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2330#else
2331 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2332 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2333#endif
2334 }
2335
2336#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2337 for (z = 0; z < 2; z++)
2338 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2339#endif
2340
2341 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2342 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2343
2344 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002345 if (emu->card_capabilities->sblive51) {
2346 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2347 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2348 *
2349 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2350 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2351 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2352 * channel. Multitrack recorders will still see the center/lfe output signal
2353 * on the second and third channels.
2354 */
2355 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2356 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2357 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2358 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2359 for (z = 4; z < 14; z++)
2360 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2361 } else {
2362 for (z = 0; z < 16; z++)
2363 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 }
Lee Revell2b637da2005-03-30 13:51:18 +02002365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
2367 if (gpr > tmp) {
2368 snd_BUG();
2369 err = -EIO;
2370 goto __err;
2371 }
2372 if (i > SND_EMU10K1_GPR_CONTROLS) {
2373 snd_BUG();
2374 err = -EIO;
2375 goto __err;
2376 }
2377
2378 /* clear remaining instruction memory */
2379 while (ptr < 0x200)
2380 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2381
2382 if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0)
2383 goto __err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 icode->gpr_add_control_count = i;
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002385 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002386 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02002387 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002388 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 if (err >= 0)
2390 err = snd_emu10k1_ipcm_poke(emu, ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002391__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 kfree(ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002393__err_ipcm:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002395__err_ctrls:
2396 kfree((void __force *)icode->gpr_map);
2397__err_gpr:
2398 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 return err;
2400}
2401
Bill Pembertone23e7a12012-12-06 12:35:10 -05002402int snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403{
Takashi Iwai09668b42005-11-17 16:14:10 +01002404 spin_lock_init(&emu->fx8010.irq_lock);
2405 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 if (emu->audigy)
2407 return _snd_emu10k1_audigy_init_efx(emu);
2408 else
2409 return _snd_emu10k1_init_efx(emu);
2410}
2411
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002412void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413{
2414 /* stop processor */
2415 if (emu->audigy)
2416 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2417 else
2418 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2419}
2420
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002421#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002422int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002424 if (output < 0 || output >= 6)
2425 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2427 return 0;
2428}
2429
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002430int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002432 if (output < 0 || output >= 6)
2433 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2435 return 0;
2436}
2437#endif
2438
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002439int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440{
2441 u8 size_reg = 0;
2442
2443 /* size is in samples */
2444 if (size != 0) {
2445 size = (size - 1) >> 13;
2446
2447 while (size) {
2448 size >>= 1;
2449 size_reg++;
2450 }
2451 size = 0x2000 << size_reg;
2452 }
2453 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2454 return 0;
2455 spin_lock_irq(&emu->emu_lock);
2456 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2457 spin_unlock_irq(&emu->emu_lock);
2458 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2459 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2460 if (emu->fx8010.etram_pages.area != NULL) {
2461 snd_dma_free_pages(&emu->fx8010.etram_pages);
2462 emu->fx8010.etram_pages.area = NULL;
2463 emu->fx8010.etram_pages.bytes = 0;
2464 }
2465
2466 if (size > 0) {
2467 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),
2468 size * 2, &emu->fx8010.etram_pages) < 0)
2469 return -ENOMEM;
2470 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2471 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2472 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2473 spin_lock_irq(&emu->emu_lock);
2474 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002475 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 }
2477
2478 return 0;
2479}
2480
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002481static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482{
2483 return 0;
2484}
2485
2486static void copy_string(char *dst, char *src, char *null, int idx)
2487{
2488 if (src == NULL)
2489 sprintf(dst, "%s %02X", null, idx);
2490 else
2491 strcpy(dst, src);
2492}
2493
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002494static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002495 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496{
2497 char **fxbus, **extin, **extout;
2498 unsigned short fxbus_mask, extin_mask, extout_mask;
2499 int res;
2500
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 info->internal_tram_size = emu->fx8010.itram_size;
2502 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2503 fxbus = fxbuses;
2504 extin = emu->audigy ? audigy_ins : creative_ins;
2505 extout = emu->audigy ? audigy_outs : creative_outs;
2506 fxbus_mask = emu->fx8010.fxbus_mask;
2507 extin_mask = emu->fx8010.extin_mask;
2508 extout_mask = emu->fx8010.extout_mask;
2509 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2510 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2511 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2512 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2513 }
2514 for (res = 16; res < 32; res++, extout++)
2515 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2516 info->gpr_controls = emu->fx8010.gpr_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517}
2518
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002519static 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 -07002520{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002521 struct snd_emu10k1 *emu = hw->private_data;
2522 struct snd_emu10k1_fx8010_info *info;
2523 struct snd_emu10k1_fx8010_code *icode;
2524 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 unsigned int addr;
2526 void __user *argp = (void __user *)arg;
2527 int res;
2528
2529 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002530 case SNDRV_EMU10K1_IOCTL_PVERSION:
2531 emu->support_tlv = 1;
2532 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 case SNDRV_EMU10K1_IOCTL_INFO:
Willy Tarreau49434c6c2018-09-08 08:12:21 +02002534 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 if (!info)
2536 return -ENOMEM;
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002537 snd_emu10k1_fx8010_info(emu, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 if (copy_to_user(argp, info, sizeof(*info))) {
2539 kfree(info);
2540 return -EFAULT;
2541 }
2542 kfree(info);
2543 return 0;
2544 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2545 if (!capable(CAP_SYS_ADMIN))
2546 return -EPERM;
Li Zefan336500f2009-04-10 09:44:31 +08002547
2548 icode = memdup_user(argp, sizeof(*icode));
2549 if (IS_ERR(icode))
2550 return PTR_ERR(icode);
Takashi Iwaid42fe632017-05-10 17:11:34 +02002551 res = snd_emu10k1_icode_poke(emu, icode, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 kfree(icode);
2553 return res;
2554 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002555 icode = memdup_user(argp, sizeof(*icode));
2556 if (IS_ERR(icode))
2557 return PTR_ERR(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 res = snd_emu10k1_icode_peek(emu, icode);
2559 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2560 kfree(icode);
2561 return -EFAULT;
2562 }
2563 kfree(icode);
2564 return res;
2565 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Li Zefan336500f2009-04-10 09:44:31 +08002566 ipcm = memdup_user(argp, sizeof(*ipcm));
2567 if (IS_ERR(ipcm))
2568 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2570 kfree(ipcm);
2571 return res;
2572 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002573 ipcm = memdup_user(argp, sizeof(*ipcm));
2574 if (IS_ERR(ipcm))
2575 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2577 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2578 kfree(ipcm);
2579 return -EFAULT;
2580 }
2581 kfree(ipcm);
2582 return res;
2583 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2584 if (!capable(CAP_SYS_ADMIN))
2585 return -EPERM;
2586 if (get_user(addr, (unsigned int __user *)argp))
2587 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002588 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002590 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 return res;
2592 case SNDRV_EMU10K1_IOCTL_STOP:
2593 if (!capable(CAP_SYS_ADMIN))
2594 return -EPERM;
2595 if (emu->audigy)
2596 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2597 else
2598 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2599 return 0;
2600 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2601 if (!capable(CAP_SYS_ADMIN))
2602 return -EPERM;
2603 if (emu->audigy)
2604 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2605 else
2606 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2607 return 0;
2608 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2609 if (!capable(CAP_SYS_ADMIN))
2610 return -EPERM;
2611 if (emu->audigy)
2612 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2613 else
2614 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2615 udelay(10);
2616 if (emu->audigy)
2617 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2618 else
2619 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2620 return 0;
2621 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2622 if (!capable(CAP_SYS_ADMIN))
2623 return -EPERM;
2624 if (get_user(addr, (unsigned int __user *)argp))
2625 return -EFAULT;
2626 if (addr > 0x1ff)
2627 return -EINVAL;
2628 if (emu->audigy)
2629 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2630 else
2631 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2632 udelay(10);
2633 if (emu->audigy)
2634 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2635 else
2636 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2637 return 0;
2638 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2639 if (emu->audigy)
2640 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2641 else
2642 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2643 if (put_user(addr, (unsigned int __user *)argp))
2644 return -EFAULT;
2645 return 0;
2646 }
2647 return -ENOTTY;
2648}
2649
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002650static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651{
2652 return 0;
2653}
2654
Lars-Peter Clausenbb814c32015-01-02 12:24:49 +01002655int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656{
Takashi Iwaieb4698f2005-11-17 14:50:13 +01002657 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 int err;
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
2661 return err;
2662 strcpy(hw->name, "EMU10K1 (FX8010)");
2663 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2664 hw->ops.open = snd_emu10k1_fx8010_open;
2665 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2666 hw->ops.release = snd_emu10k1_fx8010_release;
2667 hw->private_data = emu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 return 0;
2669}
Takashi Iwai09668b42005-11-17 16:14:10 +01002670
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002671#ifdef CONFIG_PM_SLEEP
Bill Pembertone23e7a12012-12-06 12:35:10 -05002672int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
Takashi Iwai09668b42005-11-17 16:14:10 +01002673{
2674 int len;
2675
2676 len = emu->audigy ? 0x200 : 0x100;
Kees Cook6da2ec52018-06-12 13:55:00 -07002677 emu->saved_gpr = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002678 if (! emu->saved_gpr)
2679 return -ENOMEM;
2680 len = emu->audigy ? 0x100 : 0xa0;
Kees Cook6da2ec52018-06-12 13:55:00 -07002681 emu->tram_val_saved = kmalloc_array(len, 4, GFP_KERNEL);
2682 emu->tram_addr_saved = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002683 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2684 return -ENOMEM;
2685 len = emu->audigy ? 2 * 1024 : 2 * 512;
Kees Cook42bc47b2018-06-12 14:27:11 -07002686 emu->saved_icode = vmalloc(array_size(len, 4));
Takashi Iwai09668b42005-11-17 16:14:10 +01002687 if (! emu->saved_icode)
2688 return -ENOMEM;
2689 return 0;
2690}
2691
2692void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2693{
2694 kfree(emu->saved_gpr);
2695 kfree(emu->tram_val_saved);
2696 kfree(emu->tram_addr_saved);
2697 vfree(emu->saved_icode);
2698}
2699
2700/*
2701 * save/restore GPR, TRAM and codes
2702 */
2703void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2704{
2705 int i, len;
2706
2707 len = emu->audigy ? 0x200 : 0x100;
2708 for (i = 0; i < len; i++)
2709 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2710
2711 len = emu->audigy ? 0x100 : 0xa0;
2712 for (i = 0; i < len; i++) {
2713 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2714 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2715 if (emu->audigy) {
2716 emu->tram_addr_saved[i] >>= 12;
2717 emu->tram_addr_saved[i] |=
2718 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2719 }
2720 }
2721
2722 len = emu->audigy ? 2 * 1024 : 2 * 512;
2723 for (i = 0; i < len; i++)
2724 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2725}
2726
2727void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2728{
2729 int i, len;
2730
2731 /* set up TRAM */
2732 if (emu->fx8010.etram_pages.bytes > 0) {
2733 unsigned size, size_reg = 0;
2734 size = emu->fx8010.etram_pages.bytes / 2;
2735 size = (size - 1) >> 13;
2736 while (size) {
2737 size >>= 1;
2738 size_reg++;
2739 }
2740 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2741 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2742 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2743 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2744 }
2745
2746 if (emu->audigy)
2747 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2748 else
2749 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2750
2751 len = emu->audigy ? 0x200 : 0x100;
2752 for (i = 0; i < len; i++)
2753 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2754
2755 len = emu->audigy ? 0x100 : 0xa0;
2756 for (i = 0; i < len; i++) {
2757 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2758 emu->tram_val_saved[i]);
2759 if (! emu->audigy)
2760 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2761 emu->tram_addr_saved[i]);
2762 else {
2763 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2764 emu->tram_addr_saved[i] << 12);
2765 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2766 emu->tram_addr_saved[i] >> 20);
2767 }
2768 }
2769
2770 len = emu->audigy ? 2 * 1024 : 2 * 512;
2771 for (i = 0; i < len; i++)
2772 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2773
2774 /* start FX processor when the DSP code is updated */
2775 if (emu->audigy)
2776 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2777 else
2778 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2779}
2780#endif