blob: 6cf7c8b1de47d5086b71f6e466f4e8a3d22b1d7f [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
Takashi Iwai6fddce22020-01-05 15:47:29 +010049static const char * const fxbuses[16] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 /* 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
Takashi Iwai6fddce22020-01-05 15:47:29 +010068static const char * const creative_ins[16] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 /* 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
Takashi Iwai6fddce22020-01-05 15:47:29 +010087static const char * const audigy_ins[16] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 /* 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
Takashi Iwai6fddce22020-01-05 15:47:29 +0100106static const char * const creative_outs[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 /* 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
Takashi Iwai6fddce22020-01-05 15:47:29 +0100141static const char * const audigy_outs[32] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 /* 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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-11-17 14:50:13 +0100391static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
Takashi Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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 Iwaieb4698f32005-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);
Takashi Iwai12bda102021-06-08 16:05:14 +0200439 tmp = emu->fx8010.irq_handlers;
440 if (tmp == irq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 emu->fx8010.irq_handlers = tmp->next;
442 if (emu->fx8010.irq_handlers == NULL) {
443 snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
444 emu->dsp_interrupt = NULL;
445 }
446 } else {
447 while (tmp && tmp->next != irq)
448 tmp = tmp->next;
449 if (tmp)
450 tmp->next = tmp->next->next;
451 }
452 spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return 0;
454}
455
456/*************************************************************************
457 * EMU10K1 effect manager
458 *************************************************************************/
459
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100460static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
461 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 u32 op, u32 r, u32 a, u32 x, u32 y)
463{
464 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200465 if (snd_BUG_ON(*ptr >= 512))
466 return;
Takashi Iwai81b45092020-02-02 10:07:23 +0100467 code = icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 set_bit(*ptr, icode->code_valid);
469 code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
470 code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
471 (*ptr)++;
472}
473
474#define OP(icode, ptr, op, r, a, x, y) \
475 snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
476
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100477static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
478 unsigned int *ptr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 u32 op, u32 r, u32 a, u32 x, u32 y)
480{
481 u_int32_t *code;
Takashi Iwaida3cec32008-08-08 17:12:14 +0200482 if (snd_BUG_ON(*ptr >= 1024))
483 return;
Takashi Iwai81b45092020-02-02 10:07:23 +0100484 code = icode->code + (*ptr) * 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 set_bit(*ptr, icode->code_valid);
486 code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
487 code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
488 (*ptr)++;
489}
490
491#define A_OP(icode, ptr, op, r, a, x, y) \
492 snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
493
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100494static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
497 snd_emu10k1_ptr_write(emu, pc, 0, data);
498}
499
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100500unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
503 return snd_emu10k1_ptr_read(emu, pc, 0);
504}
505
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100506static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200507 struct snd_emu10k1_fx8010_code *icode,
508 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509{
510 int gpr;
511 u32 val;
512
513 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
514 if (!test_bit(gpr, icode->gpr_valid))
515 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200516 if (in_kernel)
Takashi Iwai81b45092020-02-02 10:07:23 +0100517 val = icode->gpr_map[gpr];
518 else if (get_user(val, (__user u32 *)&icode->gpr_map[gpr]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 return -EFAULT;
520 snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
521 }
522 return 0;
523}
524
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100525static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
526 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 int gpr;
529 u32 val;
530
531 for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
532 set_bit(gpr, icode->gpr_valid);
533 val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
Takashi Iwai81b45092020-02-02 10:07:23 +0100534 if (put_user(val, (__user u32 *)&icode->gpr_map[gpr]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return -EFAULT;
536 }
537 return 0;
538}
539
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100540static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200541 struct snd_emu10k1_fx8010_code *icode,
542 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 int tram;
545 u32 addr, val;
546
547 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
548 if (!test_bit(tram, icode->tram_valid))
549 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200550 if (in_kernel) {
Takashi Iwai81b45092020-02-02 10:07:23 +0100551 val = icode->tram_data_map[tram];
552 addr = icode->tram_addr_map[tram];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200553 } else {
Takashi Iwai81b45092020-02-02 10:07:23 +0100554 if (get_user(val, (__user __u32 *)&icode->tram_data_map[tram]) ||
555 get_user(addr, (__user __u32 *)&icode->tram_addr_map[tram]))
Takashi Iwaid42fe632017-05-10 17:11:34 +0200556 return -EFAULT;
557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
559 if (!emu->audigy) {
560 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
561 } else {
562 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
563 snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
564 }
565 }
566 return 0;
567}
568
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100569static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
570 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
572 int tram;
573 u32 val, addr;
574
575 memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
576 for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
577 set_bit(tram, icode->tram_valid);
578 val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
579 if (!emu->audigy) {
580 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
581 } else {
582 addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
583 addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
584 }
Takashi Iwai81b45092020-02-02 10:07:23 +0100585 if (put_user(val, (__user u32 *)&icode->tram_data_map[tram]) ||
586 put_user(addr, (__user u32 *)&icode->tram_addr_map[tram]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return -EFAULT;
588 }
589 return 0;
590}
591
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100592static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200593 struct snd_emu10k1_fx8010_code *icode,
594 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595{
596 u32 pc, lo, hi;
597
598 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
599 if (!test_bit(pc / 2, icode->code_valid))
600 continue;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200601 if (in_kernel) {
Takashi Iwai81b45092020-02-02 10:07:23 +0100602 lo = icode->code[pc + 0];
603 hi = icode->code[pc + 1];
Takashi Iwaid42fe632017-05-10 17:11:34 +0200604 } else {
Takashi Iwai81b45092020-02-02 10:07:23 +0100605 if (get_user(lo, (__user u32 *)&icode->code[pc + 0]) ||
606 get_user(hi, (__user u32 *)&icode->code[pc + 1]))
Takashi Iwaid42fe632017-05-10 17:11:34 +0200607 return -EFAULT;
608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 snd_emu10k1_efx_write(emu, pc + 0, lo);
610 snd_emu10k1_efx_write(emu, pc + 1, hi);
611 }
612 return 0;
613}
614
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100615static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
616 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617{
618 u32 pc;
619
620 memset(icode->code_valid, 0, sizeof(icode->code_valid));
621 for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
622 set_bit(pc / 2, icode->code_valid);
Takashi Iwai81b45092020-02-02 10:07:23 +0100623 if (put_user(snd_emu10k1_efx_read(emu, pc + 0),
624 (__user u32 *)&icode->code[pc + 0]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return -EFAULT;
Takashi Iwai81b45092020-02-02 10:07:23 +0100626 if (put_user(snd_emu10k1_efx_read(emu, pc + 1),
627 (__user u32 *)&icode->code[pc + 1]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return -EFAULT;
629 }
630 return 0;
631}
632
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100633static struct snd_emu10k1_fx8010_ctl *
Takashi Iwai81b45092020-02-02 10:07:23 +0100634snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu,
635 struct emu10k1_ctl_elem_id *_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636{
Takashi Iwai81b45092020-02-02 10:07:23 +0100637 struct snd_ctl_elem_id *id = (struct snd_ctl_elem_id *)_id;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100638 struct snd_emu10k1_fx8010_ctl *ctl;
639 struct snd_kcontrol *kcontrol;
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200640
641 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 kcontrol = ctl->kcontrol;
643 if (kcontrol->id.iface == id->iface &&
644 !strcmp(kcontrol->id.name, id->name) &&
645 kcontrol->id.index == id->index)
646 return ctl;
647 }
648 return NULL;
649}
650
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100651#define MAX_TLV_SIZE 256
652
Takashi Iwaid42fe632017-05-10 17:11:34 +0200653static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100654{
655 unsigned int data[2];
656 unsigned int *tlv;
657
658 if (!_tlv)
659 return NULL;
Takashi Iwaid42fe632017-05-10 17:11:34 +0200660 if (in_kernel)
Takashi Iwai63623642018-07-25 23:00:57 +0200661 memcpy(data, (__force void *)_tlv, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200662 else if (copy_from_user(data, _tlv, sizeof(data)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100663 return NULL;
664 if (data[1] >= MAX_TLV_SIZE)
665 return NULL;
Takashi Iwai6735e572008-01-19 10:33:07 +0100666 tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100667 if (!tlv)
668 return NULL;
669 memcpy(tlv, data, sizeof(data));
Takashi Iwaid42fe632017-05-10 17:11:34 +0200670 if (in_kernel) {
Takashi Iwai63623642018-07-25 23:00:57 +0200671 memcpy(tlv + 2, (__force void *)(_tlv + 2), data[1]);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200672 } else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100673 kfree(tlv);
674 return NULL;
675 }
676 return tlv;
677}
678
679static int copy_gctl(struct snd_emu10k1 *emu,
Takashi Iwai81b45092020-02-02 10:07:23 +0100680 struct snd_emu10k1_fx8010_control_gpr *dst,
681 struct snd_emu10k1_fx8010_control_gpr *src,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200682 int idx, bool in_kernel)
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100683{
Takashi Iwai81b45092020-02-02 10:07:23 +0100684 struct snd_emu10k1_fx8010_control_gpr __user *_src;
685 struct snd_emu10k1_fx8010_control_old_gpr *octl;
686 struct snd_emu10k1_fx8010_control_old_gpr __user *_octl;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100687
Takashi Iwai81b45092020-02-02 10:07:23 +0100688 _src = (struct snd_emu10k1_fx8010_control_gpr __user *)src;
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200689 if (emu->support_tlv) {
690 if (in_kernel)
Takashi Iwai81b45092020-02-02 10:07:23 +0100691 *dst = src[idx];
692 else if (copy_from_user(dst, &_src[idx], sizeof(*src)))
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200693 return -EFAULT;
694 return 0;
695 }
696
Takashi Iwai81b45092020-02-02 10:07:23 +0100697 octl = (struct snd_emu10k1_fx8010_control_old_gpr *)src;
698 _octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)octl;
Takashi Iwai0b36f2b2017-08-18 10:55:10 +0200699 if (in_kernel)
Takashi Iwai81b45092020-02-02 10:07:23 +0100700 memcpy(dst, &octl[idx], sizeof(*octl));
701 else if (copy_from_user(dst, &_octl[idx], sizeof(*octl)))
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100702 return -EFAULT;
Takashi Iwai81b45092020-02-02 10:07:23 +0100703 dst->tlv = NULL;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100704 return 0;
705}
706
707static int copy_gctl_to_user(struct snd_emu10k1 *emu,
Takashi Iwai81b45092020-02-02 10:07:23 +0100708 struct snd_emu10k1_fx8010_control_gpr *dst,
709 struct snd_emu10k1_fx8010_control_gpr *src,
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100710 int idx)
711{
Takashi Iwai81b45092020-02-02 10:07:23 +0100712 struct snd_emu10k1_fx8010_control_gpr __user *_dst;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100713 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
714
Takashi Iwai81b45092020-02-02 10:07:23 +0100715 _dst = (struct snd_emu10k1_fx8010_control_gpr __user *)dst;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100716 if (emu->support_tlv)
Takashi Iwai81b45092020-02-02 10:07:23 +0100717 return copy_to_user(&_dst[idx], src, sizeof(*src));
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100718
Takashi Iwai81b45092020-02-02 10:07:23 +0100719 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)dst;
720 return copy_to_user(&octl[idx], src, sizeof(*octl));
721}
722
723static int copy_ctl_elem_id(const struct emu10k1_ctl_elem_id *list, int i,
724 struct emu10k1_ctl_elem_id *ret, bool in_kernel)
725{
726 struct emu10k1_ctl_elem_id __user *_id =
727 (struct emu10k1_ctl_elem_id __user *)&list[i];
728
729 if (in_kernel)
730 *ret = list[i];
731 else if (copy_from_user(ret, _id, sizeof(*ret)))
732 return -EFAULT;
733 return 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100734}
735
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100736static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200737 struct snd_emu10k1_fx8010_code *icode,
738 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739{
740 unsigned int i;
Takashi Iwai2e468862019-12-20 16:34:11 +0100741 struct emu10k1_ctl_elem_id id;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100742 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwai81b45092020-02-02 10:07:23 +0100743 struct snd_ctl_elem_id *gctl_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 int err;
745
Takashi Iwai81b45092020-02-02 10:07:23 +0100746 for (i = 0; i < icode->gpr_del_control_count; i++) {
747 err = copy_ctl_elem_id(icode->gpr_del_controls, i, &id,
748 in_kernel);
749 if (err < 0)
750 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
752 return -ENOENT;
753 }
754 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
755 if (! gctl)
756 return -ENOMEM;
757 err = 0;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100758 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200759 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
760 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 err = -EFAULT;
762 goto __error;
763 }
764 if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
765 continue;
Takashi Iwai81b45092020-02-02 10:07:23 +0100766 gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 down_read(&emu->card->controls_rwsem);
Takashi Iwai81b45092020-02-02 10:07:23 +0100768 if (snd_ctl_find_id(emu->card, gctl_id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 up_read(&emu->card->controls_rwsem);
770 err = -EEXIST;
771 goto __error;
772 }
773 up_read(&emu->card->controls_rwsem);
Takashi Iwai81b45092020-02-02 10:07:23 +0100774 if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
775 gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 err = -EINVAL;
777 goto __error;
778 }
779 }
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100780 for (i = 0; i < icode->gpr_list_control_count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 /* FIXME: we need to check the WRITE access */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200782 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i,
783 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 err = -EFAULT;
785 goto __error;
786 }
787 }
788 __error:
789 kfree(gctl);
790 return err;
791}
792
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100793static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100795 struct snd_emu10k1_fx8010_ctl *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100797 ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 kctl->private_value = 0;
799 list_del(&ctl->list);
800 kfree(ctl);
Markus Elfring31604d32014-11-03 14:54:36 +0100801 kfree(kctl->tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100804static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200805 struct snd_emu10k1_fx8010_code *icode,
806 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 unsigned int i, j;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100809 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwai81b45092020-02-02 10:07:23 +0100810 struct snd_ctl_elem_id *gctl_id;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100811 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
812 struct snd_kcontrol_new knew;
813 struct snd_kcontrol *kctl;
814 struct snd_ctl_elem_value *val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 int err = 0;
816
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100817 val = kmalloc(sizeof(*val), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
819 nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
820 if (!val || !gctl || !nctl) {
821 err = -ENOMEM;
822 goto __error;
823 }
824
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100825 for (i = 0; i < icode->gpr_add_control_count; i++) {
Takashi Iwaid42fe632017-05-10 17:11:34 +0200826 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
827 in_kernel)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 err = -EFAULT;
829 goto __error;
830 }
Takashi Iwai81b45092020-02-02 10:07:23 +0100831 gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
832 if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
833 gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200834 err = -EINVAL;
835 goto __error;
836 }
Takashi Iwai81b45092020-02-02 10:07:23 +0100837 if (!*gctl_id->name) {
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200838 err = -EINVAL;
839 goto __error;
840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
842 memset(&knew, 0, sizeof(knew));
Takashi Iwai81b45092020-02-02 10:07:23 +0100843 knew.iface = gctl_id->iface;
844 knew.name = gctl_id->name;
845 knew.index = gctl_id->index;
846 knew.device = gctl_id->device;
847 knew.subdevice = gctl_id->subdevice;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 knew.info = snd_emu10k1_gpr_ctl_info;
Takashi Iwai81b45092020-02-02 10:07:23 +0100849 knew.tlv.p = copy_tlv((const unsigned int __user *)gctl->tlv, in_kernel);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100850 if (knew.tlv.p)
James Courtier-Dutton31508f82006-07-22 17:02:10 +0100851 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
852 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 knew.get = snd_emu10k1_gpr_ctl_get;
854 knew.put = snd_emu10k1_gpr_ctl_put;
855 memset(nctl, 0, sizeof(*nctl));
856 nctl->vcount = gctl->vcount;
857 nctl->count = gctl->count;
858 for (j = 0; j < 32; j++) {
859 nctl->gpr[j] = gctl->gpr[j];
860 nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
861 val->value.integer.value[j] = gctl->value[j];
862 }
863 nctl->min = gctl->min;
864 nctl->max = gctl->max;
865 nctl->translation = gctl->translation;
866 if (ctl == NULL) {
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100867 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (ctl == NULL) {
869 err = -ENOMEM;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100870 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 goto __error;
872 }
873 knew.private_value = (unsigned long)ctl;
874 *ctl = *nctl;
Takashi Iwai12bda102021-06-08 16:05:14 +0200875 kctl = snd_ctl_new1(&knew, emu);
876 err = snd_ctl_add(emu->card, kctl);
877 if (err < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 kfree(ctl);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100879 kfree(knew.tlv.p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 goto __error;
881 }
882 kctl->private_free = snd_emu10k1_ctl_private_free;
883 ctl->kcontrol = kctl;
884 list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
885 } else {
886 /* overwrite */
887 nctl->list = ctl->list;
888 nctl->kcontrol = ctl->kcontrol;
889 *ctl = *nctl;
890 snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
891 SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
892 }
893 snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
894 }
895 __error:
896 kfree(nctl);
897 kfree(gctl);
898 kfree(val);
899 return err;
900}
901
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100902static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200903 struct snd_emu10k1_fx8010_code *icode,
904 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
906 unsigned int i;
Takashi Iwai2e468862019-12-20 16:34:11 +0100907 struct emu10k1_ctl_elem_id id;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100908 struct snd_emu10k1_fx8010_ctl *ctl;
909 struct snd_card *card = emu->card;
Takashi Iwai81b45092020-02-02 10:07:23 +0100910 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Takashi Iwai81b45092020-02-02 10:07:23 +0100912 for (i = 0; i < icode->gpr_del_control_count; i++) {
913 err = copy_ctl_elem_id(icode->gpr_del_controls, i, &id,
914 in_kernel);
915 if (err < 0)
916 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 down_write(&card->controls_rwsem);
918 ctl = snd_emu10k1_look_for_ctl(emu, &id);
919 if (ctl)
920 snd_ctl_remove(card, ctl->kcontrol);
921 up_write(&card->controls_rwsem);
922 }
923 return 0;
924}
925
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100926static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
927 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
929 unsigned int i = 0, j;
930 unsigned int total = 0;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100931 struct snd_emu10k1_fx8010_control_gpr *gctl;
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100932 struct snd_emu10k1_fx8010_ctl *ctl;
933 struct snd_ctl_elem_id *id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
936 if (! gctl)
937 return -ENOMEM;
938
Matthias Kaehlckec2d70512007-09-17 14:41:16 +0200939 list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 total++;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100941 if (icode->gpr_list_controls &&
942 i < icode->gpr_list_control_count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 memset(gctl, 0, sizeof(*gctl));
944 id = &ctl->kcontrol->id;
Takashi Iwai81b45092020-02-02 10:07:23 +0100945 gctl->id.iface = (__force int)id->iface;
Joe Perches75b1a8f2021-01-04 09:17:34 -0800946 strscpy(gctl->id.name, id->name, sizeof(gctl->id.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 gctl->id.index = id->index;
948 gctl->id.device = id->device;
949 gctl->id.subdevice = id->subdevice;
950 gctl->vcount = ctl->vcount;
951 gctl->count = ctl->count;
952 for (j = 0; j < 32; j++) {
953 gctl->gpr[j] = ctl->gpr[j];
954 gctl->value[j] = ctl->value[j];
955 }
956 gctl->min = ctl->min;
957 gctl->max = ctl->max;
958 gctl->translation = ctl->translation;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +0100959 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
960 gctl, i)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 kfree(gctl);
962 return -EFAULT;
963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 i++;
965 }
966 }
967 icode->gpr_list_control_total = total;
968 kfree(gctl);
969 return 0;
970}
971
Takashi Iwaieb4698f32005-11-17 14:50:13 +0100972static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
Takashi Iwaid42fe632017-05-10 17:11:34 +0200973 struct snd_emu10k1_fx8010_code *icode,
974 bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
976 int err = 0;
977
Ingo Molnar62932df2006-01-16 16:34:20 +0100978 mutex_lock(&emu->fx8010.lock);
Takashi Iwaid42fe632017-05-10 17:11:34 +0200979 err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
980 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 goto __error;
Joe Perches75b1a8f2021-01-04 09:17:34 -0800982 strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* stop FX processor - this may be dangerous, but it's better to miss
984 some samples than generate wrong ones - [jk] */
985 if (emu->audigy)
986 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
987 else
988 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
989 /* ok, do the main job */
Takashi Iwaid42fe632017-05-10 17:11:34 +0200990 err = snd_emu10k1_del_controls(emu, icode, in_kernel);
991 if (err < 0)
992 goto __error;
993 err = snd_emu10k1_gpr_poke(emu, icode, in_kernel);
994 if (err < 0)
995 goto __error;
996 err = snd_emu10k1_tram_poke(emu, icode, in_kernel);
997 if (err < 0)
998 goto __error;
999 err = snd_emu10k1_code_poke(emu, icode, in_kernel);
1000 if (err < 0)
1001 goto __error;
1002 err = snd_emu10k1_add_controls(emu, icode, in_kernel);
1003 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 goto __error;
1005 /* start FX processor when the DSP code is updated */
1006 if (emu->audigy)
1007 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
1008 else
1009 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
1010 __error:
Ingo Molnar62932df2006-01-16 16:34:20 +01001011 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return err;
1013}
1014
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001015static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
1016 struct snd_emu10k1_fx8010_code *icode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017{
1018 int err;
1019
Ingo Molnar62932df2006-01-16 16:34:20 +01001020 mutex_lock(&emu->fx8010.lock);
Joe Perches75b1a8f2021-01-04 09:17:34 -08001021 strscpy(icode->name, emu->fx8010.name, sizeof(icode->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 /* ok, do the main job */
1023 err = snd_emu10k1_gpr_peek(emu, icode);
1024 if (err >= 0)
1025 err = snd_emu10k1_tram_peek(emu, icode);
1026 if (err >= 0)
1027 err = snd_emu10k1_code_peek(emu, icode);
1028 if (err >= 0)
1029 err = snd_emu10k1_list_controls(emu, icode);
Ingo Molnar62932df2006-01-16 16:34:20 +01001030 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return err;
1032}
1033
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001034static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
1035 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
1037 unsigned int i;
1038 int err = 0;
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001039 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
1041 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1042 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001043 ipcm->substream = array_index_nospec(ipcm->substream,
1044 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (ipcm->channels > 32)
1046 return -EINVAL;
1047 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001048 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 spin_lock_irq(&emu->reg_lock);
1050 if (pcm->opened) {
1051 err = -EBUSY;
1052 goto __error;
1053 }
1054 if (ipcm->channels == 0) { /* remove */
1055 pcm->valid = 0;
1056 } else {
1057 /* FIXME: we need to add universal code to the PCM transfer routine */
1058 if (ipcm->channels != 2) {
1059 err = -EINVAL;
1060 goto __error;
1061 }
1062 pcm->valid = 1;
1063 pcm->opened = 0;
1064 pcm->channels = ipcm->channels;
1065 pcm->tram_start = ipcm->tram_start;
1066 pcm->buffer_size = ipcm->buffer_size;
1067 pcm->gpr_size = ipcm->gpr_size;
1068 pcm->gpr_count = ipcm->gpr_count;
1069 pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
1070 pcm->gpr_ptr = ipcm->gpr_ptr;
1071 pcm->gpr_trigger = ipcm->gpr_trigger;
1072 pcm->gpr_running = ipcm->gpr_running;
1073 for (i = 0; i < pcm->channels; i++)
1074 pcm->etram[i] = ipcm->etram[i];
1075 }
1076 __error:
1077 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001078 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 return err;
1080}
1081
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001082static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1083 struct snd_emu10k1_fx8010_pcm_rec *ipcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084{
1085 unsigned int i;
1086 int err = 0;
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001087 struct snd_emu10k1_fx8010_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
1090 return -EINVAL;
Gustavo A. R. Silva5ae4f612018-12-18 11:52:16 -06001091 ipcm->substream = array_index_nospec(ipcm->substream,
1092 EMU10K1_FX8010_PCM_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 pcm = &emu->fx8010.pcm[ipcm->substream];
Ingo Molnar62932df2006-01-16 16:34:20 +01001094 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 spin_lock_irq(&emu->reg_lock);
1096 ipcm->channels = pcm->channels;
1097 ipcm->tram_start = pcm->tram_start;
1098 ipcm->buffer_size = pcm->buffer_size;
1099 ipcm->gpr_size = pcm->gpr_size;
1100 ipcm->gpr_ptr = pcm->gpr_ptr;
1101 ipcm->gpr_count = pcm->gpr_count;
1102 ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
1103 ipcm->gpr_trigger = pcm->gpr_trigger;
1104 ipcm->gpr_running = pcm->gpr_running;
1105 for (i = 0; i < pcm->channels; i++)
1106 ipcm->etram[i] = pcm->etram[i];
1107 ipcm->res1 = ipcm->res2 = 0;
1108 ipcm->pad = 0;
1109 spin_unlock_irq(&emu->reg_lock);
Ingo Molnar62932df2006-01-16 16:34:20 +01001110 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return err;
1112}
1113
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001114#define SND_EMU10K1_GPR_CONTROLS 44
1115#define SND_EMU10K1_INPUTS 12
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116#define SND_EMU10K1_PLAYBACK_CHANNELS 8
1117#define SND_EMU10K1_CAPTURE_CHANNELS 4
1118
Bill Pembertone23e7a12012-12-06 12:35:10 -05001119static void
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001120snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1121 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122{
Takashi Iwai81b45092020-02-02 10:07:23 +01001123 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 strcpy(ctl->id.name, name);
1125 ctl->vcount = ctl->count = 1;
1126 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001127 if (high_res_gpr_volume) {
1128 ctl->min = 0;
1129 ctl->max = 0x7fffffff;
1130 ctl->tlv = snd_emu10k1_db_linear;
1131 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1132 } else {
1133 ctl->min = 0;
1134 ctl->max = 100;
1135 ctl->tlv = snd_emu10k1_db_scale1;
1136 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138}
1139
Bill Pembertone23e7a12012-12-06 12:35:10 -05001140static void
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001141snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1142 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143{
Takashi Iwai81b45092020-02-02 10:07:23 +01001144 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 strcpy(ctl->id.name, name);
1146 ctl->vcount = ctl->count = 2;
1147 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1148 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
Clemens Ladisch4daf7a02010-05-25 09:04:49 +02001149 if (high_res_gpr_volume) {
1150 ctl->min = 0;
1151 ctl->max = 0x7fffffff;
1152 ctl->tlv = snd_emu10k1_db_linear;
1153 ctl->translation = EMU10K1_GPR_TRANSLATION_NONE;
1154 } else {
1155 ctl->min = 0;
1156 ctl->max = 100;
1157 ctl->tlv = snd_emu10k1_db_scale1;
1158 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160}
1161
Bill Pembertone23e7a12012-12-06 12:35:10 -05001162static void
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001163snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1164 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Takashi Iwai81b45092020-02-02 10:07:23 +01001166 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 strcpy(ctl->id.name, name);
1168 ctl->vcount = ctl->count = 1;
1169 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1170 ctl->min = 0;
1171 ctl->max = 1;
1172 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1173}
1174
Bill Pembertone23e7a12012-12-06 12:35:10 -05001175static void
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001176snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1177 const char *name, int gpr, int defval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
Takashi Iwai81b45092020-02-02 10:07:23 +01001179 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 strcpy(ctl->id.name, name);
1181 ctl->vcount = ctl->count = 2;
1182 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1183 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1184 ctl->min = 0;
1185 ctl->max = 1;
1186 ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
1187}
1188
Pavel Hofman13d45702007-06-11 12:21:20 +02001189/*
1190 * Used for emu1010 - conversion from 32-bit capture inputs from HANA
1191 * to 2 x 16-bit registers in audigy - their values are read via DMA.
1192 * Conversion is performed by Audigy DSP instructions of FX8010.
1193 */
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001194static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1195 struct snd_emu10k1_fx8010_code *icode,
1196 u32 *ptr, int tmp, int bit_shifter16,
1197 int reg_in, int reg_out)
1198{
1199 A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000);
1200 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000);
1201 A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2));
1202 A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000);
1203 A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000);
1204 A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000);
1205 A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2));
1206 A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000);
1207 return 1;
1208}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210/*
1211 * initial DSP configuration for Audigy
1212 */
1213
Bill Pembertone23e7a12012-12-06 12:35:10 -05001214static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
1216 int err, i, z, gpr, nctl;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001217 int bit_shifter16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 const int playback = 10;
1219 const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */
1220 const int stereo_mix = capture + 2;
1221 const int tmp = 0x88;
1222 u32 ptr;
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001223 struct snd_emu10k1_fx8010_code *icode = NULL;
1224 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001227 err = -ENOMEM;
1228 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1229 if (!icode)
1230 return err;
1231
Takashi Iwai81b45092020-02-02 10:07:23 +01001232 icode->gpr_map = kcalloc(512 + 256 + 256 + 2 * 1024,
1233 sizeof(u_int32_t), GFP_KERNEL);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001234 if (!icode->gpr_map)
1235 goto __err_gpr;
1236 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1237 sizeof(*controls), GFP_KERNEL);
1238 if (!controls)
1239 goto __err_ctrls;
1240
Takashi Iwai81b45092020-02-02 10:07:23 +01001241 gpr_map = icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
1243 icode->tram_data_map = icode->gpr_map + 512;
1244 icode->tram_addr_map = icode->tram_data_map + 256;
1245 icode->code = icode->tram_addr_map + 256;
1246
1247 /* clear free GPRs */
1248 for (i = 0; i < 512; i++)
1249 set_bit(i, icode->gpr_valid);
1250
1251 /* clear TRAM data & address lines */
1252 for (i = 0; i < 256; i++)
1253 set_bit(i, icode->tram_valid);
1254
1255 strcpy(icode->name, "Audigy DSP code for ALSA");
1256 ptr = 0;
1257 nctl = 0;
1258 gpr = stereo_mix + 10;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001259 gpr_map[gpr++] = 0x00007fff;
1260 gpr_map[gpr++] = 0x00008000;
1261 gpr_map[gpr++] = 0x0000ffff;
1262 bit_shifter16 = gpr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 /* stop FX processor */
1265 snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
1266
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001267#if 1
Pavel Hofman13d45702007-06-11 12:21:20 +02001268 /* PCM front Playback Volume (independent from stereo mix)
1269 * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
1270 * where gpr contains attenuation from corresponding mixer control
1271 * (snd_emu10k1_init_stereo_control)
1272 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
1274 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
1275 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
1276 gpr += 2;
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 /* PCM Surround Playback (independent from stereo mix) */
1279 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
1280 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
1281 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
1282 gpr += 2;
1283
1284 /* PCM Side Playback (independent from stereo mix) */
Lee Revell2b637da2005-03-30 13:51:18 +02001285 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
1287 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
1288 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
1289 gpr += 2;
1290 }
1291
1292 /* PCM Center Playback (independent from stereo mix) */
1293 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
1294 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
1295 gpr++;
1296
1297 /* PCM LFE Playback (independent from stereo mix) */
1298 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
1299 snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
1300 gpr++;
1301
1302 /*
1303 * Stereo Mix
1304 */
1305 /* Wave (PCM) Playback Volume (will be renamed later) */
1306 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1307 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1308 snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
1309 gpr += 2;
1310
1311 /* Synth Playback */
1312 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1313 A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1314 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
1315 gpr += 2;
1316
1317 /* Wave (PCM) Capture */
1318 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
1319 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
1320 snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
1321 gpr += 2;
1322
1323 /* Synth Capture */
1324 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
1325 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
1326 snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
1327 gpr += 2;
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 /*
1330 * inputs
1331 */
1332#define A_ADD_VOLUME_IN(var,vol,input) \
1333A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1334
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001335 /* emu1212 DSP 0 and DSP 1 Capture */
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001336 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001337 if (emu->card_capabilities->ca0108_chip) {
1338 /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */
1339 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001);
1340 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp));
1341 A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001);
1342 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp));
1343 } else {
1344 A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0));
1345 A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1));
1346 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001347 snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1348 gpr += 2;
1349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* AC'97 Playback Volume - used only for mic (renamed later) */
1351 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
1352 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
1353 snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
1354 gpr += 2;
1355 /* AC'97 Capture Volume - used only for mic */
1356 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
1357 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
1358 snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
1359 gpr += 2;
1360
1361 /* mic capture buffer */
1362 A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R));
1363
1364 /* Audigy CD Playback Volume */
1365 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
1366 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1367 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001368 emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 gpr, 0);
1370 gpr += 2;
1371 /* Audigy CD Capture Volume */
1372 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
1373 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
1374 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001375 emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 gpr, 0);
1377 gpr += 2;
1378
1379 /* Optical SPDIF Playback Volume */
1380 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
1381 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001382 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 gpr += 2;
1384 /* Optical SPDIF Capture Volume */
1385 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
1386 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001387 snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 gpr += 2;
1389
1390 /* Line2 Playback Volume */
1391 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
1392 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
1393 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001394 emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 gpr, 0);
1396 gpr += 2;
1397 /* Line2 Capture Volume */
1398 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
1399 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
1400 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001401 emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 gpr, 0);
1403 gpr += 2;
1404
1405 /* Philips ADC Playback Volume */
1406 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
1407 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
1408 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
1409 gpr += 2;
1410 /* Philips ADC Capture Volume */
1411 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
1412 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
1413 snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
1414 gpr += 2;
1415
1416 /* Aux2 Playback Volume */
1417 A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
1418 A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
1419 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001420 emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 gpr, 0);
1422 gpr += 2;
1423 /* Aux2 Capture Volume */
1424 A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
1425 A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
1426 snd_emu10k1_init_stereo_control(&controls[nctl++],
Lee Revell2b637da2005-03-30 13:51:18 +02001427 emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 gpr, 0);
1429 gpr += 2;
1430
1431 /* Stereo Mix Front Playback Volume */
1432 A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
1433 A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1434 snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
1435 gpr += 2;
1436
1437 /* Stereo Mix Surround Playback */
1438 A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
1439 A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1440 snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
1441 gpr += 2;
1442
1443 /* Stereo Mix Center Playback */
1444 /* Center = sub = Left/2 + Right/2 */
1445 A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1));
1446 A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
1447 snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
1448 gpr++;
1449
1450 /* Stereo Mix LFE Playback */
1451 A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
1452 snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
1453 gpr++;
1454
Lee Revell2b637da2005-03-30 13:51:18 +02001455 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 /* Stereo Mix Side Playback */
1457 A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
1458 A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
1459 snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
1460 gpr += 2;
1461 }
1462
1463 /*
1464 * outputs
1465 */
1466#define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
1467#define A_PUT_STEREO_OUTPUT(out1,out2,src) \
1468 {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
1469
1470#define _A_SWITCH(icode, ptr, dst, src, sw) \
1471 A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
1472#define A_SWITCH(icode, ptr, dst, src, sw) \
1473 _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
1474#define _A_SWITCH_NEG(icode, ptr, dst, src) \
1475 A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
1476#define A_SWITCH_NEG(icode, ptr, dst, src) \
1477 _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
1478
1479
1480 /*
1481 * Process tone control
1482 */
1483 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */
1484 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */
1485 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 */
1486 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 */
1487 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */
1488 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 +02001489 if (emu->card_capabilities->spk71) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 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 */
1491 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 */
1492 }
1493
1494
1495 ctl = &controls[nctl + 0];
Takashi Iwai81b45092020-02-02 10:07:23 +01001496 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 strcpy(ctl->id.name, "Tone Control - Bass");
1498 ctl->vcount = 2;
1499 ctl->count = 10;
1500 ctl->min = 0;
1501 ctl->max = 40;
1502 ctl->value[0] = ctl->value[1] = 20;
1503 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
1504 ctl = &controls[nctl + 1];
Takashi Iwai81b45092020-02-02 10:07:23 +01001505 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 strcpy(ctl->id.name, "Tone Control - Treble");
1507 ctl->vcount = 2;
1508 ctl->count = 10;
1509 ctl->min = 0;
1510 ctl->max = 40;
1511 ctl->value[0] = ctl->value[1] = 20;
1512 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
1513
1514#define BASS_GPR 0x8c
1515#define TREBLE_GPR 0x96
1516
1517 for (z = 0; z < 5; z++) {
1518 int j;
1519 for (j = 0; j < 2; j++) {
1520 controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
1521 controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
1522 }
1523 }
1524 for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
1525 int j, k, l, d;
1526 for (j = 0; j < 2; j++) { /* left/right */
1527 k = 0xb0 + (z * 8) + (j * 4);
1528 l = 0xe0 + (z * 8) + (j * 4);
1529 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
1530
1531 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j));
1532 A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j));
1533 A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j));
1534 A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j));
1535 A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j));
1536 A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
1537
1538 A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j));
1539 A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j));
1540 A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j));
1541 A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j));
1542 A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j));
1543 A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
1544
1545 A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
1546
1547 if (z == 2) /* center */
1548 break;
1549 }
1550 }
1551 nctl += 2;
1552
1553#undef BASS_GPR
1554#undef TREBLE_GPR
1555
1556 for (z = 0; z < 8; z++) {
1557 A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
1558 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
1559 A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
1560 A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1561 }
1562 snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
1563 gpr += 2;
1564
1565 /* Master volume (will be renamed later) */
1566 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));
1567 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));
1568 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));
1569 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));
1570 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));
1571 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));
1572 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));
1573 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));
1574 snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1575 gpr += 2;
1576
1577 /* analog speakers */
1578 A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1579 A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1580 A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1581 A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
Lee Revell2b637da2005-03-30 13:51:18 +02001582 if (emu->card_capabilities->spk71)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS);
1584
1585 /* headphone */
1586 A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1587
1588 /* digital outputs */
1589 /* 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 +00001590 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001591 /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
Takashi Iwai6f002b02014-02-25 17:02:09 +01001592 dev_info(emu->card->dev, "EMU outputs on\n");
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001593 for (z = 0; z < 8; z++) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001594 if (emu->card_capabilities->ca0108_chip) {
1595 A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1596 } else {
1597 A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000);
1598 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001599 }
1600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 /* IEC958 Optical Raw Playback Switch */
1603 gpr_map[gpr++] = 0;
1604 gpr_map[gpr++] = 0x1008;
1605 gpr_map[gpr++] = 0xffff0000;
1606 for (z = 0; z < 2; z++) {
1607 A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
1608 A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
1609 A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
1610 A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
1611 A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
1612 A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
1613 A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
1614 if ((z==1) && (emu->card_capabilities->spdif_bug)) {
1615 /* 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 +01001616 dev_info(emu->card->dev,
1617 "Installing spdif_bug patch: %s\n",
1618 emu->card_capabilities->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
1620 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1621 } else {
1622 A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
1623 }
1624 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02001625 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 -07001626 gpr += 2;
1627
1628 A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
1629 A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS);
1630 A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS);
1631
1632 /* ADC buffer */
1633#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
1634 A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS);
1635#else
1636 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
1637 A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
1638#endif
1639
James Courtier-Dutton190d2c42007-11-04 14:08:26 +00001640 if (emu->card_capabilities->emu_model) {
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001641 if (emu->card_capabilities->ca0108_chip) {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001642 dev_info(emu->card->dev, "EMU2 inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001643 for (z = 0; z < 0x10; z++) {
1644 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
1645 bit_shifter16,
1646 A3_EMU32IN(z),
1647 A_FXBUS2(z*2) );
1648 }
1649 } else {
Takashi Iwai6f002b02014-02-25 17:02:09 +01001650 dev_info(emu->card->dev, "EMU inputs on\n");
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001651 /* Capture 16 (originally 8) channels of S32_LE sound */
1652
Takashi Iwai28a97c12009-02-05 16:08:14 +01001653 /*
Takashi Iwai6f002b02014-02-25 17:02:09 +01001654 dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
Takashi Iwai28a97c12009-02-05 16:08:14 +01001655 gpr, tmp);
1656 */
James Courtier-Dutton90fd5ce2007-07-23 14:01:46 +01001657 /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
1658 /* A_P16VIN(0) is delayed by one sample,
1659 * so all other A_P16VIN channels will need to also be delayed
1660 */
1661 /* Left ADC in. 1 of 2 */
1662 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
1663 /* Right ADC in 1 of 2 */
1664 gpr_map[gpr++] = 0x00000000;
1665 /* Delaying by one sample: instead of copying the input
1666 * value A_P16VIN to output A_FXBUS2 as in the first channel,
1667 * we use an auxiliary register, delaying the value by one
1668 * sample
1669 */
1670 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
1671 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
1672 gpr_map[gpr++] = 0x00000000;
1673 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) );
1674 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000);
1675 gpr_map[gpr++] = 0x00000000;
1676 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) );
1677 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000);
1678 /* For 96kHz mode */
1679 /* Left ADC in. 2 of 2 */
1680 gpr_map[gpr++] = 0x00000000;
1681 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) );
1682 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000);
1683 /* Right ADC in 2 of 2 */
1684 gpr_map[gpr++] = 0x00000000;
1685 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) );
1686 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000);
1687 gpr_map[gpr++] = 0x00000000;
1688 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) );
1689 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000);
1690 gpr_map[gpr++] = 0x00000000;
1691 snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
1692 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
1693 /* Pavel Hofman - we still have voices, A_FXBUS2s, and
1694 * A_P16VINs available -
1695 * let's add 8 more capture channels - total of 16
1696 */
1697 gpr_map[gpr++] = 0x00000000;
1698 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1699 bit_shifter16,
1700 A_GPR(gpr - 1),
1701 A_FXBUS2(0x10));
1702 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
1703 A_C_00000000, A_C_00000000);
1704 gpr_map[gpr++] = 0x00000000;
1705 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1706 bit_shifter16,
1707 A_GPR(gpr - 1),
1708 A_FXBUS2(0x12));
1709 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
1710 A_C_00000000, A_C_00000000);
1711 gpr_map[gpr++] = 0x00000000;
1712 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1713 bit_shifter16,
1714 A_GPR(gpr - 1),
1715 A_FXBUS2(0x14));
1716 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
1717 A_C_00000000, A_C_00000000);
1718 gpr_map[gpr++] = 0x00000000;
1719 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1720 bit_shifter16,
1721 A_GPR(gpr - 1),
1722 A_FXBUS2(0x16));
1723 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
1724 A_C_00000000, A_C_00000000);
1725 gpr_map[gpr++] = 0x00000000;
1726 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1727 bit_shifter16,
1728 A_GPR(gpr - 1),
1729 A_FXBUS2(0x18));
1730 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
1731 A_C_00000000, A_C_00000000);
1732 gpr_map[gpr++] = 0x00000000;
1733 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1734 bit_shifter16,
1735 A_GPR(gpr - 1),
1736 A_FXBUS2(0x1a));
1737 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
1738 A_C_00000000, A_C_00000000);
1739 gpr_map[gpr++] = 0x00000000;
1740 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1741 bit_shifter16,
1742 A_GPR(gpr - 1),
1743 A_FXBUS2(0x1c));
1744 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
1745 A_C_00000000, A_C_00000000);
1746 gpr_map[gpr++] = 0x00000000;
1747 snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
1748 bit_shifter16,
1749 A_GPR(gpr - 1),
1750 A_FXBUS2(0x1e));
1751 A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
1752 A_C_00000000, A_C_00000000);
1753 }
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01001754
1755#if 0
1756 for (z = 4; z < 8; z++) {
1757 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1758 }
1759 for (z = 0xc; z < 0x10; z++) {
1760 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
1761 }
1762#endif
1763 } else {
1764 /* EFX capture - capture the 16 EXTINs */
1765 /* Capture 16 channels of S16_LE sound */
1766 for (z = 0; z < 16; z++) {
1767 A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
1768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
1770
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001771#endif /* JCD test */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 /*
1773 * ok, set up done..
1774 */
1775
1776 if (gpr > tmp) {
1777 snd_BUG();
1778 err = -EIO;
1779 goto __err;
1780 }
1781 /* clear remaining instruction memory */
1782 while (ptr < 0x400)
1783 A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
1784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 icode->gpr_add_control_count = nctl;
Takashi Iwai81b45092020-02-02 10:07:23 +01001786 icode->gpr_add_controls = controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001787 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02001788 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01001789 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001791__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001793__err_ctrls:
Takashi Iwai81b45092020-02-02 10:07:23 +01001794 kfree(icode->gpr_map);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001795__err_gpr:
1796 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 return err;
1798}
1799
1800
1801/*
1802 * initial DSP configuration for Emu10k1
1803 */
1804
1805/* when volume = max, then copy only to avoid volume modification */
1806/* with iMAC0 (negative values) */
Bill Pembertone23e7a12012-12-06 12:35:10 -05001807static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808{
1809 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1810 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1811 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001);
1812 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1813}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001814static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815{
1816 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1817 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1818 OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001);
1819 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1820 OP(icode, ptr, iMAC0, dst, dst, src, vol);
1821}
Bill Pembertone23e7a12012-12-06 12:35:10 -05001822static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823{
1824 OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff);
1825 OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1826 OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000);
1827 OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001);
1828 OP(icode, ptr, iMAC0, dst, C_00000000, src, vol);
1829}
1830
1831#define VOLUME(icode, ptr, dst, src, vol) \
1832 _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1833#define VOLUME_IN(icode, ptr, dst, src, vol) \
1834 _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1835#define VOLUME_ADD(icode, ptr, dst, src, vol) \
1836 _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
1837#define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
1838 _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
1839#define VOLUME_OUT(icode, ptr, dst, src, vol) \
1840 _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
1841#define _SWITCH(icode, ptr, dst, src, sw) \
1842 OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
1843#define SWITCH(icode, ptr, dst, src, sw) \
1844 _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
1845#define SWITCH_IN(icode, ptr, dst, src, sw) \
1846 _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
1847#define _SWITCH_NEG(icode, ptr, dst, src) \
1848 OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
1849#define SWITCH_NEG(icode, ptr, dst, src) \
1850 _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
1851
1852
Bill Pembertone23e7a12012-12-06 12:35:10 -05001853static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854{
1855 int err, i, z, gpr, tmp, playback, capture;
1856 u32 ptr;
Takashi Iwaieb4698f32005-11-17 14:50:13 +01001857 struct snd_emu10k1_fx8010_code *icode;
1858 struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1859 struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 u32 *gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001862 err = -ENOMEM;
1863 icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1864 if (!icode)
1865 return err;
1866
Takashi Iwai81b45092020-02-02 10:07:23 +01001867 icode->gpr_map = kcalloc(256 + 160 + 160 + 2 * 512,
1868 sizeof(u_int32_t), GFP_KERNEL);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03001869 if (!icode->gpr_map)
1870 goto __err_gpr;
1871
1872 controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1873 sizeof(struct snd_emu10k1_fx8010_control_gpr),
1874 GFP_KERNEL);
1875 if (!controls)
1876 goto __err_ctrls;
1877
1878 ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
1879 if (!ipcm)
1880 goto __err_ipcm;
1881
Takashi Iwai81b45092020-02-02 10:07:23 +01001882 gpr_map = icode->gpr_map;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883
1884 icode->tram_data_map = icode->gpr_map + 256;
1885 icode->tram_addr_map = icode->tram_data_map + 160;
1886 icode->code = icode->tram_addr_map + 160;
1887
1888 /* clear free GPRs */
1889 for (i = 0; i < 256; i++)
1890 set_bit(i, icode->gpr_valid);
1891
1892 /* clear TRAM data & address lines */
1893 for (i = 0; i < 160; i++)
1894 set_bit(i, icode->tram_valid);
1895
1896 strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
1897 ptr = 0; i = 0;
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001898 /* we have 12 inputs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 playback = SND_EMU10K1_INPUTS;
1900 /* we have 6 playback channels and tone control doubles */
1901 capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2);
1902 gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
1903 tmp = 0x88; /* we need 4 temporary GPR */
1904 /* from 0x8c to 0xff is the area for tone control */
1905
1906 /* stop FX processor */
1907 snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP);
1908
1909 /*
1910 * Process FX Buses
1911 */
1912 OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004);
1913 OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004);
1914 OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004);
1915 OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004);
1916 OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004);
1917 OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004);
1918 OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004);
1919 OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004);
1920 OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
1921 OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
Mikael Magnussonedf8e452005-09-13 11:32:58 +02001922 OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004);
1923 OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 /* Raw S/PDIF PCM */
1926 ipcm->substream = 0;
1927 ipcm->channels = 2;
1928 ipcm->tram_start = 0;
1929 ipcm->buffer_size = (64 * 1024) / 2;
1930 ipcm->gpr_size = gpr++;
1931 ipcm->gpr_ptr = gpr++;
1932 ipcm->gpr_count = gpr++;
1933 ipcm->gpr_tmpcount = gpr++;
1934 ipcm->gpr_trigger = gpr++;
1935 ipcm->gpr_running = gpr++;
1936 ipcm->etram[0] = 0;
1937 ipcm->etram[1] = 1;
1938
1939 gpr_map[gpr + 0] = 0xfffff000;
1940 gpr_map[gpr + 1] = 0xffff0000;
1941 gpr_map[gpr + 2] = 0x70000000;
1942 gpr_map[gpr + 3] = 0x00000007;
1943 gpr_map[gpr + 4] = 0x001f << 11;
1944 gpr_map[gpr + 5] = 0x001c << 11;
1945 gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
1946 gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
1947 gpr_map[gpr + 8] = 0x2000000 + (2<<11);
1948 gpr_map[gpr + 9] = 0x4000000 + (2<<11);
1949 gpr_map[gpr + 10] = 1<<11;
1950 gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
1951 gpr_map[gpr + 12] = 0;
1952
1953 /* if the trigger flag is not set, skip */
1954 /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
1955 /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
1956 /* if the running flag is set, we're running */
1957 /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
1958 /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
1959 /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
1960 /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
1961 /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
1962 /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
1963 /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
1964
1965 /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
1966 /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
1967 /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
1968 /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
1969
1970 /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
1971 /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1972 /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1973 /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1974 /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
1975
1976 /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
1977 /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
1978 /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
1979 /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
1980 /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
1981
1982 /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
1983 /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
1984 /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
1985 /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
1986 /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
1987
1988 /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
1989 /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
1990 /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
1991 /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
1992 /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
1993
1994 /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
1995 /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
1996
1997 /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
1998 /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
1999
2000 /* 24: */
2001 gpr += 13;
2002
2003 /* Wave Playback Volume */
2004 for (z = 0; z < 2; z++)
2005 VOLUME(icode, &ptr, playback + z, z, gpr + z);
2006 snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
2007 gpr += 2;
2008
2009 /* Wave Surround Playback Volume */
2010 for (z = 0; z < 2; z++)
2011 VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
2012 snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
2013 gpr += 2;
2014
2015 /* Wave Center/LFE Playback Volume */
2016 OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
2017 OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002);
2018 VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
2019 snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
2020 VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
2021 snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
2022
2023 /* Wave Capture Volume + Switch */
2024 for (z = 0; z < 2; z++) {
2025 SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
2026 VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
2027 }
2028 snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
2029 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
2030 gpr += 4;
2031
2032 /* Synth Playback Volume */
2033 for (z = 0; z < 2; z++)
2034 VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
2035 snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
2036 gpr += 2;
2037
2038 /* Synth Capture Volume + Switch */
2039 for (z = 0; z < 2; z++) {
2040 SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
2041 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2042 }
2043 snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
2044 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
2045 gpr += 4;
2046
2047 /* Surround Digital Playback Volume (renamed later without Digital) */
2048 for (z = 0; z < 2; z++)
2049 VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
2050 snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
2051 gpr += 2;
2052
2053 /* Surround Capture Volume + Switch */
2054 for (z = 0; z < 2; z++) {
2055 SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
2056 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2057 }
2058 snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
2059 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
2060 gpr += 4;
2061
2062 /* Center Playback Volume (renamed later without Digital) */
2063 VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
2064 snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
2065
2066 /* LFE Playback Volume + Switch (renamed later without Digital) */
2067 VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
2068 snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
2069
Mikael Magnussonedf8e452005-09-13 11:32:58 +02002070 /* Front Playback Volume */
2071 for (z = 0; z < 2; z++)
2072 VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
2073 snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
2074 gpr += 2;
2075
2076 /* Front Capture Volume + Switch */
2077 for (z = 0; z < 2; z++) {
2078 SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
2079 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2080 }
2081 snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2082 snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2083 gpr += 3;
2084
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 /*
2086 * Process inputs
2087 */
2088
2089 if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
2090 /* AC'97 Playback Volume */
2091 VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
2092 VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
2093 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
2094 /* AC'97 Capture Volume */
2095 VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
2096 VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
2097 snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
2098 }
2099
2100 if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
2101 /* IEC958 TTL Playback Volume */
2102 for (z = 0; z < 2; z++)
2103 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002104 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 gpr += 2;
2106
2107 /* IEC958 TTL Capture Volume + Switch */
2108 for (z = 0; z < 2; z++) {
2109 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
2110 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2111 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002112 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
2113 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 -07002114 gpr += 4;
2115 }
2116
2117 if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
2118 /* Zoom Video Playback Volume */
2119 for (z = 0; z < 2; z++)
2120 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
2121 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
2122 gpr += 2;
2123
2124 /* Zoom Video Capture Volume + Switch */
2125 for (z = 0; z < 2; z++) {
2126 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
2127 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2128 }
2129 snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
2130 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
2131 gpr += 4;
2132 }
2133
2134 if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
2135 /* IEC958 Optical Playback Volume */
2136 for (z = 0; z < 2; z++)
2137 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002138 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 gpr += 2;
2140
2141 /* IEC958 Optical Capture Volume */
2142 for (z = 0; z < 2; z++) {
2143 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
2144 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2145 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002146 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
2147 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 -07002148 gpr += 4;
2149 }
2150
2151 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
2152 /* Line LiveDrive Playback Volume */
2153 for (z = 0; z < 2; z++)
2154 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
2155 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
2156 gpr += 2;
2157
2158 /* Line LiveDrive Capture Volume + Switch */
2159 for (z = 0; z < 2; z++) {
2160 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
2161 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2162 }
2163 snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
2164 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
2165 gpr += 4;
2166 }
2167
2168 if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
2169 /* IEC958 Coax Playback Volume */
2170 for (z = 0; z < 2; z++)
2171 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002172 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 gpr += 2;
2174
2175 /* IEC958 Coax Capture Volume + Switch */
2176 for (z = 0; z < 2; z++) {
2177 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
2178 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2179 }
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002180 snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
2181 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 -07002182 gpr += 4;
2183 }
2184
2185 if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
2186 /* Line LiveDrive Playback Volume */
2187 for (z = 0; z < 2; z++)
2188 VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
2189 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
2190 controls[i-1].id.index = 1;
2191 gpr += 2;
2192
2193 /* Line LiveDrive Capture Volume */
2194 for (z = 0; z < 2; z++) {
2195 SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
2196 VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2197 }
2198 snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
2199 controls[i-1].id.index = 1;
2200 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
2201 controls[i-1].id.index = 1;
2202 gpr += 4;
2203 }
2204
2205 /*
2206 * Process tone control
2207 */
2208 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */
2209 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */
2210 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */
2211 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */
2212 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */
2213 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */
2214
2215 ctl = &controls[i + 0];
Takashi Iwai81b45092020-02-02 10:07:23 +01002216 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 strcpy(ctl->id.name, "Tone Control - Bass");
2218 ctl->vcount = 2;
2219 ctl->count = 10;
2220 ctl->min = 0;
2221 ctl->max = 40;
2222 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002223 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
2225 ctl = &controls[i + 1];
Takashi Iwai81b45092020-02-02 10:07:23 +01002226 ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 strcpy(ctl->id.name, "Tone Control - Treble");
2228 ctl->vcount = 2;
2229 ctl->count = 10;
2230 ctl->min = 0;
2231 ctl->max = 40;
2232 ctl->value[0] = ctl->value[1] = 20;
Raymond Yaubfe9fc8a2011-05-20 14:32:04 +08002233 ctl->tlv = snd_emu10k1_bass_treble_db_scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
2235
2236#define BASS_GPR 0x8c
2237#define TREBLE_GPR 0x96
2238
2239 for (z = 0; z < 5; z++) {
2240 int j;
2241 for (j = 0; j < 2; j++) {
2242 controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
2243 controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
2244 }
2245 }
2246 for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
2247 int j, k, l, d;
2248 for (j = 0; j < 2; j++) { /* left/right */
2249 k = 0xa0 + (z * 8) + (j * 4);
2250 l = 0xd0 + (z * 8) + (j * 4);
2251 d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j;
2252
2253 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
2254 OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
2255 OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
2256 OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
2257 OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
2258 OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
2259
2260 OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
2261 OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
2262 OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
2263 OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
2264 OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
2265 OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
2266
2267 OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
2268
2269 if (z == 2) /* center */
2270 break;
2271 }
2272 }
2273 i += 2;
2274
2275#undef BASS_GPR
2276#undef TREBLE_GPR
2277
2278 for (z = 0; z < 6; z++) {
2279 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0);
2280 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0);
2281 SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
2282 OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2283 }
2284 snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
2285 gpr += 2;
2286
2287 /*
2288 * Process outputs
2289 */
2290 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
2291 /* AC'97 Playback Volume */
2292
2293 for (z = 0; z < 2; z++)
2294 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000);
2295 }
2296
2297 if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
2298 /* IEC958 Optical Raw Playback Switch */
2299
2300 for (z = 0; z < 2; z++) {
2301 SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
2302 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
2303 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2304 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2305#ifdef EMU10K1_CAPTURE_DIGITAL_OUT
2306 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2307#endif
2308 }
2309
Clemens Ladisch10e8d782005-08-03 13:40:08 +02002310 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 -07002311 gpr += 2;
2312 }
2313
2314 if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
2315 /* Headphone Playback Volume */
2316
2317 for (z = 0; z < 2; z++) {
2318 SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z);
2319 SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
2320 SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1);
2321 OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
2322 VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
2323 }
2324
2325 snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
2326 controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
2327 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
2328 controls[i-1].id.index = 1;
2329 snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
2330 controls[i-1].id.index = 1;
2331
2332 gpr += 4;
2333 }
2334
2335 if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
2336 for (z = 0; z < 2; z++)
2337 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2338
2339 if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
2340 for (z = 0; z < 2; z++)
2341 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000);
2342
2343 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
2344#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2345 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2346 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000);
2347#else
2348 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2349 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000);
2350#endif
2351 }
2352
2353 if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
2354#ifndef EMU10K1_CENTER_LFE_FROM_FRONT
2355 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2356 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000);
2357#else
2358 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2359 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000);
2360#endif
2361 }
2362
2363#ifndef EMU10K1_CAPTURE_DIGITAL_OUT
2364 for (z = 0; z < 2; z++)
2365 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
2366#endif
2367
2368 if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
2369 OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
2370
2371 /* EFX capture - capture the 16 EXTINS */
Lee Revell2b637da2005-03-30 13:51:18 +02002372 if (emu->card_capabilities->sblive51) {
2373 /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER
2374 * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
2375 *
2376 * Since only 14 of the 16 EXTINs are used, this is not a big problem.
2377 * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture
2378 * 0 and 3, then the rest of the EXTINs to the corresponding FX capture
2379 * channel. Multitrack recorders will still see the center/lfe output signal
2380 * on the second and third channels.
2381 */
2382 OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0));
2383 OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1));
2384 OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2));
2385 OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3));
2386 for (z = 4; z < 14; z++)
2387 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
2388 } else {
2389 for (z = 0; z < 16; z++)
2390 OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 }
Lee Revell2b637da2005-03-30 13:51:18 +02002392
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393
2394 if (gpr > tmp) {
2395 snd_BUG();
2396 err = -EIO;
2397 goto __err;
2398 }
2399 if (i > SND_EMU10K1_GPR_CONTROLS) {
2400 snd_BUG();
2401 err = -EIO;
2402 goto __err;
2403 }
2404
2405 /* clear remaining instruction memory */
2406 while (ptr < 0x200)
2407 OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
2408
Takashi Iwai12bda102021-06-08 16:05:14 +02002409 err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size);
2410 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 goto __err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 icode->gpr_add_control_count = i;
Takashi Iwai81b45092020-02-02 10:07:23 +01002413 icode->gpr_add_controls = controls;
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002414 emu->support_tlv = 1; /* support TLV */
Takashi Iwaid42fe632017-05-10 17:11:34 +02002415 err = snd_emu10k1_icode_poke(emu, icode, true);
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002416 emu->support_tlv = 0; /* clear again */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 if (err >= 0)
2418 err = snd_emu10k1_ipcm_poke(emu, ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002419__err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 kfree(ipcm);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002421__err_ipcm:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 kfree(controls);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002423__err_ctrls:
Takashi Iwai81b45092020-02-02 10:07:23 +01002424 kfree(icode->gpr_map);
Geyslan G. Bemf1b48632013-10-17 19:57:12 -03002425__err_gpr:
2426 kfree(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 return err;
2428}
2429
Bill Pembertone23e7a12012-12-06 12:35:10 -05002430int snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431{
Takashi Iwai09668b42005-11-17 16:14:10 +01002432 spin_lock_init(&emu->fx8010.irq_lock);
2433 INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 if (emu->audigy)
2435 return _snd_emu10k1_audigy_init_efx(emu);
2436 else
2437 return _snd_emu10k1_init_efx(emu);
2438}
2439
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002440void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441{
2442 /* stop processor */
2443 if (emu->audigy)
2444 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
2445 else
2446 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
2447}
2448
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +01002449#if 0 /* FIXME: who use them? */
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002450int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002452 if (output < 0 || output >= 6)
2453 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
2455 return 0;
2456}
2457
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002458int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
Takashi Iwai7c22f1a2005-10-10 11:46:31 +02002460 if (output < 0 || output >= 6)
2461 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
2463 return 0;
2464}
2465#endif
2466
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002467int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468{
2469 u8 size_reg = 0;
2470
2471 /* size is in samples */
2472 if (size != 0) {
2473 size = (size - 1) >> 13;
2474
2475 while (size) {
2476 size >>= 1;
2477 size_reg++;
2478 }
2479 size = 0x2000 << size_reg;
2480 }
2481 if ((emu->fx8010.etram_pages.bytes / 2) == size)
2482 return 0;
2483 spin_lock_irq(&emu->emu_lock);
2484 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2485 spin_unlock_irq(&emu->emu_lock);
2486 snd_emu10k1_ptr_write(emu, TCB, 0, 0);
2487 snd_emu10k1_ptr_write(emu, TCBS, 0, 0);
2488 if (emu->fx8010.etram_pages.area != NULL) {
2489 snd_dma_free_pages(&emu->fx8010.etram_pages);
2490 emu->fx8010.etram_pages.area = NULL;
2491 emu->fx8010.etram_pages.bytes = 0;
2492 }
2493
2494 if (size > 0) {
Takashi Iwai6974f8a2019-11-05 16:18:55 +01002495 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 size * 2, &emu->fx8010.etram_pages) < 0)
2497 return -ENOMEM;
2498 memset(emu->fx8010.etram_pages.area, 0, size * 2);
2499 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2500 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2501 spin_lock_irq(&emu->emu_lock);
2502 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
Takashi Iwai09668b42005-11-17 16:14:10 +01002503 spin_unlock_irq(&emu->emu_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 }
2505
2506 return 0;
2507}
2508
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002509static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510{
2511 return 0;
2512}
2513
Takashi Iwai6fddce22020-01-05 15:47:29 +01002514static void copy_string(char *dst, const char *src, const char *null, int idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
2516 if (src == NULL)
2517 sprintf(dst, "%s %02X", null, idx);
2518 else
2519 strcpy(dst, src);
2520}
2521
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002522static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002523 struct snd_emu10k1_fx8010_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524{
Takashi Iwai6fddce22020-01-05 15:47:29 +01002525 const char * const *fxbus, * const *extin, * const *extout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 unsigned short fxbus_mask, extin_mask, extout_mask;
2527 int res;
2528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 info->internal_tram_size = emu->fx8010.itram_size;
2530 info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2531 fxbus = fxbuses;
2532 extin = emu->audigy ? audigy_ins : creative_ins;
2533 extout = emu->audigy ? audigy_outs : creative_outs;
2534 fxbus_mask = emu->fx8010.fxbus_mask;
2535 extin_mask = emu->fx8010.extin_mask;
2536 extout_mask = emu->fx8010.extout_mask;
2537 for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2538 copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res);
2539 copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
2540 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2541 }
2542 for (res = 16; res < 32; res++, extout++)
2543 copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
2544 info->gpr_controls = emu->fx8010.gpr_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545}
2546
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002547static 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 -07002548{
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002549 struct snd_emu10k1 *emu = hw->private_data;
2550 struct snd_emu10k1_fx8010_info *info;
2551 struct snd_emu10k1_fx8010_code *icode;
2552 struct snd_emu10k1_fx8010_pcm_rec *ipcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 unsigned int addr;
2554 void __user *argp = (void __user *)arg;
2555 int res;
2556
2557 switch (cmd) {
Takashi Iwaif7ba7fc2007-01-19 18:34:47 +01002558 case SNDRV_EMU10K1_IOCTL_PVERSION:
2559 emu->support_tlv = 1;
2560 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 case SNDRV_EMU10K1_IOCTL_INFO:
Willy Tarreau49434c6c2018-09-08 08:12:21 +02002562 info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 if (!info)
2564 return -ENOMEM;
Mariusz Kozlowski51882452007-08-11 11:06:09 +02002565 snd_emu10k1_fx8010_info(emu, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 if (copy_to_user(argp, info, sizeof(*info))) {
2567 kfree(info);
2568 return -EFAULT;
2569 }
2570 kfree(info);
2571 return 0;
2572 case SNDRV_EMU10K1_IOCTL_CODE_POKE:
2573 if (!capable(CAP_SYS_ADMIN))
2574 return -EPERM;
Li Zefan336500f2009-04-10 09:44:31 +08002575
2576 icode = memdup_user(argp, sizeof(*icode));
2577 if (IS_ERR(icode))
2578 return PTR_ERR(icode);
Takashi Iwaid42fe632017-05-10 17:11:34 +02002579 res = snd_emu10k1_icode_poke(emu, icode, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 kfree(icode);
2581 return res;
2582 case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002583 icode = memdup_user(argp, sizeof(*icode));
2584 if (IS_ERR(icode))
2585 return PTR_ERR(icode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 res = snd_emu10k1_icode_peek(emu, icode);
2587 if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
2588 kfree(icode);
2589 return -EFAULT;
2590 }
2591 kfree(icode);
2592 return res;
2593 case SNDRV_EMU10K1_IOCTL_PCM_POKE:
Li Zefan336500f2009-04-10 09:44:31 +08002594 ipcm = memdup_user(argp, sizeof(*ipcm));
2595 if (IS_ERR(ipcm))
2596 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 res = snd_emu10k1_ipcm_poke(emu, ipcm);
2598 kfree(ipcm);
2599 return res;
2600 case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
Li Zefan336500f2009-04-10 09:44:31 +08002601 ipcm = memdup_user(argp, sizeof(*ipcm));
2602 if (IS_ERR(ipcm))
2603 return PTR_ERR(ipcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 res = snd_emu10k1_ipcm_peek(emu, ipcm);
2605 if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
2606 kfree(ipcm);
2607 return -EFAULT;
2608 }
2609 kfree(ipcm);
2610 return res;
2611 case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
2612 if (!capable(CAP_SYS_ADMIN))
2613 return -EPERM;
2614 if (get_user(addr, (unsigned int __user *)argp))
2615 return -EFAULT;
Ingo Molnar62932df2006-01-16 16:34:20 +01002616 mutex_lock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 res = snd_emu10k1_fx8010_tram_setup(emu, addr);
Ingo Molnar62932df2006-01-16 16:34:20 +01002618 mutex_unlock(&emu->fx8010.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 return res;
2620 case SNDRV_EMU10K1_IOCTL_STOP:
2621 if (!capable(CAP_SYS_ADMIN))
2622 return -EPERM;
2623 if (emu->audigy)
2624 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
2625 else
2626 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
2627 return 0;
2628 case SNDRV_EMU10K1_IOCTL_CONTINUE:
2629 if (!capable(CAP_SYS_ADMIN))
2630 return -EPERM;
2631 if (emu->audigy)
2632 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
2633 else
2634 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
2635 return 0;
2636 case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
2637 if (!capable(CAP_SYS_ADMIN))
2638 return -EPERM;
2639 if (emu->audigy)
2640 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
2641 else
2642 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
2643 udelay(10);
2644 if (emu->audigy)
2645 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2646 else
2647 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2648 return 0;
2649 case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
2650 if (!capable(CAP_SYS_ADMIN))
2651 return -EPERM;
2652 if (get_user(addr, (unsigned int __user *)argp))
2653 return -EFAULT;
2654 if (addr > 0x1ff)
2655 return -EINVAL;
2656 if (emu->audigy)
2657 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr);
2658 else
2659 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr);
2660 udelay(10);
2661 if (emu->audigy)
2662 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr);
2663 else
2664 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr);
2665 return 0;
2666 case SNDRV_EMU10K1_IOCTL_DBG_READ:
2667 if (emu->audigy)
2668 addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
2669 else
2670 addr = snd_emu10k1_ptr_read(emu, DBG, 0);
2671 if (put_user(addr, (unsigned int __user *)argp))
2672 return -EFAULT;
2673 return 0;
2674 }
2675 return -ENOTTY;
2676}
2677
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002678static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679{
2680 return 0;
2681}
2682
Lars-Peter Clausenbb814c32015-01-02 12:24:49 +01002683int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
Takashi Iwaieb4698f32005-11-17 14:50:13 +01002685 struct snd_hwdep *hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 int err;
2687
Takashi Iwai12bda102021-06-08 16:05:14 +02002688 err = snd_hwdep_new(emu->card, "FX8010", device, &hw);
2689 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 return err;
2691 strcpy(hw->name, "EMU10K1 (FX8010)");
2692 hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
2693 hw->ops.open = snd_emu10k1_fx8010_open;
2694 hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
2695 hw->ops.release = snd_emu10k1_fx8010_release;
2696 hw->private_data = emu;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return 0;
2698}
Takashi Iwai09668b42005-11-17 16:14:10 +01002699
Takashi Iwaic7561cd2012-08-14 18:12:04 +02002700#ifdef CONFIG_PM_SLEEP
Bill Pembertone23e7a12012-12-06 12:35:10 -05002701int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
Takashi Iwai09668b42005-11-17 16:14:10 +01002702{
2703 int len;
2704
2705 len = emu->audigy ? 0x200 : 0x100;
Kees Cook6da2ec52018-06-12 13:55:00 -07002706 emu->saved_gpr = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002707 if (! emu->saved_gpr)
2708 return -ENOMEM;
2709 len = emu->audigy ? 0x100 : 0xa0;
Kees Cook6da2ec52018-06-12 13:55:00 -07002710 emu->tram_val_saved = kmalloc_array(len, 4, GFP_KERNEL);
2711 emu->tram_addr_saved = kmalloc_array(len, 4, GFP_KERNEL);
Takashi Iwai09668b42005-11-17 16:14:10 +01002712 if (! emu->tram_val_saved || ! emu->tram_addr_saved)
2713 return -ENOMEM;
2714 len = emu->audigy ? 2 * 1024 : 2 * 512;
Kees Cook42bc47b2018-06-12 14:27:11 -07002715 emu->saved_icode = vmalloc(array_size(len, 4));
Takashi Iwai09668b42005-11-17 16:14:10 +01002716 if (! emu->saved_icode)
2717 return -ENOMEM;
2718 return 0;
2719}
2720
2721void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
2722{
2723 kfree(emu->saved_gpr);
2724 kfree(emu->tram_val_saved);
2725 kfree(emu->tram_addr_saved);
2726 vfree(emu->saved_icode);
2727}
2728
2729/*
2730 * save/restore GPR, TRAM and codes
2731 */
2732void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
2733{
2734 int i, len;
2735
2736 len = emu->audigy ? 0x200 : 0x100;
2737 for (i = 0; i < len; i++)
2738 emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
2739
2740 len = emu->audigy ? 0x100 : 0xa0;
2741 for (i = 0; i < len; i++) {
2742 emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
2743 emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
2744 if (emu->audigy) {
2745 emu->tram_addr_saved[i] >>= 12;
2746 emu->tram_addr_saved[i] |=
2747 snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
2748 }
2749 }
2750
2751 len = emu->audigy ? 2 * 1024 : 2 * 512;
2752 for (i = 0; i < len; i++)
2753 emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
2754}
2755
2756void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
2757{
2758 int i, len;
2759
2760 /* set up TRAM */
2761 if (emu->fx8010.etram_pages.bytes > 0) {
2762 unsigned size, size_reg = 0;
2763 size = emu->fx8010.etram_pages.bytes / 2;
2764 size = (size - 1) >> 13;
2765 while (size) {
2766 size >>= 1;
2767 size_reg++;
2768 }
2769 outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
2770 snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
2771 snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
2772 outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
2773 }
2774
2775 if (emu->audigy)
2776 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
2777 else
2778 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
2779
2780 len = emu->audigy ? 0x200 : 0x100;
2781 for (i = 0; i < len; i++)
2782 snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
2783
2784 len = emu->audigy ? 0x100 : 0xa0;
2785 for (i = 0; i < len; i++) {
2786 snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
2787 emu->tram_val_saved[i]);
2788 if (! emu->audigy)
2789 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2790 emu->tram_addr_saved[i]);
2791 else {
2792 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2793 emu->tram_addr_saved[i] << 12);
2794 snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
2795 emu->tram_addr_saved[i] >> 20);
2796 }
2797 }
2798
2799 len = emu->audigy ? 2 * 1024 : 2 * 512;
2800 for (i = 0; i < len; i++)
2801 snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
2802
2803 /* start FX processor when the DSP code is updated */
2804 if (emu->audigy)
2805 snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
2806 else
2807 snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
2808}
2809#endif