11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4*6d68d9cbSOswald Buddenhagen * James Courtier-Dutton <James@superbug.co.uk>
5*6d68d9cbSOswald Buddenhagen * Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
61da177e4SLinus Torvalds * Creative Labs, Inc.
71da177e4SLinus Torvalds *
8*6d68d9cbSOswald Buddenhagen * Routines for effect processor FX8010
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/pci.h>
12c59ede7bSRandy.Dunlap #include <linux/capability.h>
131da177e4SLinus Torvalds #include <linux/delay.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
15bd01e7bcSAndreas Schwab #include <linux/vmalloc.h>
161da177e4SLinus Torvalds #include <linux/init.h>
1762932df8SIngo Molnar #include <linux/mutex.h>
184daf7a0cSClemens Ladisch #include <linux/moduleparam.h>
195ae4f61fSGustavo A. R. Silva #include <linux/nospec.h>
2062932df8SIngo Molnar
211da177e4SLinus Torvalds #include <sound/core.h>
2231508f83SJames Courtier-Dutton #include <sound/tlv.h>
231da177e4SLinus Torvalds #include <sound/emu10k1.h>
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #if 0 /* for testing purposes - digital out -> capture */
261da177e4SLinus Torvalds #define EMU10K1_CAPTURE_DIGITAL_OUT
271da177e4SLinus Torvalds #endif
281da177e4SLinus Torvalds #if 0 /* for testing purposes - set S/PDIF to AC3 output */
291da177e4SLinus Torvalds #define EMU10K1_SET_AC3_IEC958
301da177e4SLinus Torvalds #endif
311da177e4SLinus Torvalds #if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */
321da177e4SLinus Torvalds #define EMU10K1_CENTER_LFE_FROM_FRONT
331da177e4SLinus Torvalds #endif
341da177e4SLinus Torvalds
354daf7a0cSClemens Ladisch static bool high_res_gpr_volume;
364daf7a0cSClemens Ladisch module_param(high_res_gpr_volume, bool, 0444);
374daf7a0cSClemens Ladisch MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range.");
384daf7a0cSClemens Ladisch
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds * Tables
411da177e4SLinus Torvalds */
421da177e4SLinus Torvalds
43db987421SOswald Buddenhagen // Playback channel labels; corresponds with the public FXBUS_* defines.
44db987421SOswald Buddenhagen // Unlike the tables below, this is not determined by the hardware.
45db987421SOswald Buddenhagen const char * const snd_emu10k1_fxbus[32] = {
461da177e4SLinus Torvalds /* 0x00 */ "PCM Left",
471da177e4SLinus Torvalds /* 0x01 */ "PCM Right",
48db987421SOswald Buddenhagen /* 0x02 */ "PCM Rear Left",
49db987421SOswald Buddenhagen /* 0x03 */ "PCM Rear Right",
501da177e4SLinus Torvalds /* 0x04 */ "MIDI Left",
511da177e4SLinus Torvalds /* 0x05 */ "MIDI Right",
52db987421SOswald Buddenhagen /* 0x06 */ "PCM Center",
53db987421SOswald Buddenhagen /* 0x07 */ "PCM LFE",
54db987421SOswald Buddenhagen /* 0x08 */ "PCM Front Left",
55db987421SOswald Buddenhagen /* 0x09 */ "PCM Front Right",
561da177e4SLinus Torvalds /* 0x0a */ NULL,
571da177e4SLinus Torvalds /* 0x0b */ NULL,
581da177e4SLinus Torvalds /* 0x0c */ "MIDI Reverb",
591da177e4SLinus Torvalds /* 0x0d */ "MIDI Chorus",
60db987421SOswald Buddenhagen /* 0x0e */ "PCM Side Left",
61db987421SOswald Buddenhagen /* 0x0f */ "PCM Side Right",
62db987421SOswald Buddenhagen /* 0x10 */ NULL,
63db987421SOswald Buddenhagen /* 0x11 */ NULL,
64db987421SOswald Buddenhagen /* 0x12 */ NULL,
65db987421SOswald Buddenhagen /* 0x13 */ NULL,
66db987421SOswald Buddenhagen /* 0x14 */ "Passthrough Left",
67db987421SOswald Buddenhagen /* 0x15 */ "Passthrough Right",
68db987421SOswald Buddenhagen /* 0x16 */ NULL,
69db987421SOswald Buddenhagen /* 0x17 */ NULL,
70db987421SOswald Buddenhagen /* 0x18 */ NULL,
71db987421SOswald Buddenhagen /* 0x19 */ NULL,
72db987421SOswald Buddenhagen /* 0x1a */ NULL,
73db987421SOswald Buddenhagen /* 0x1b */ NULL,
74db987421SOswald Buddenhagen /* 0x1c */ NULL,
75db987421SOswald Buddenhagen /* 0x1d */ NULL,
76db987421SOswald Buddenhagen /* 0x1e */ NULL,
77db987421SOswald Buddenhagen /* 0x1f */ NULL
781da177e4SLinus Torvalds };
791da177e4SLinus Torvalds
80db987421SOswald Buddenhagen // Physical inputs; corresponds with the public EXTIN_* defines.
81db987421SOswald Buddenhagen const char * const snd_emu10k1_sblive_ins[16] = {
821da177e4SLinus Torvalds /* 0x00 */ "AC97 Left",
831da177e4SLinus Torvalds /* 0x01 */ "AC97 Right",
841da177e4SLinus Torvalds /* 0x02 */ "TTL IEC958 Left",
851da177e4SLinus Torvalds /* 0x03 */ "TTL IEC958 Right",
861da177e4SLinus Torvalds /* 0x04 */ "Zoom Video Left",
871da177e4SLinus Torvalds /* 0x05 */ "Zoom Video Right",
881da177e4SLinus Torvalds /* 0x06 */ "Optical IEC958 Left",
891da177e4SLinus Torvalds /* 0x07 */ "Optical IEC958 Right",
901da177e4SLinus Torvalds /* 0x08 */ "Line/Mic 1 Left",
911da177e4SLinus Torvalds /* 0x09 */ "Line/Mic 1 Right",
921da177e4SLinus Torvalds /* 0x0a */ "Coaxial IEC958 Left",
931da177e4SLinus Torvalds /* 0x0b */ "Coaxial IEC958 Right",
941da177e4SLinus Torvalds /* 0x0c */ "Line/Mic 2 Left",
951da177e4SLinus Torvalds /* 0x0d */ "Line/Mic 2 Right",
961da177e4SLinus Torvalds /* 0x0e */ NULL,
971da177e4SLinus Torvalds /* 0x0f */ NULL
981da177e4SLinus Torvalds };
991da177e4SLinus Torvalds
100db987421SOswald Buddenhagen // Physical inputs; corresponds with the public A_EXTIN_* defines.
101db987421SOswald Buddenhagen const char * const snd_emu10k1_audigy_ins[16] = {
1021da177e4SLinus Torvalds /* 0x00 */ "AC97 Left",
1031da177e4SLinus Torvalds /* 0x01 */ "AC97 Right",
1041da177e4SLinus Torvalds /* 0x02 */ "Audigy CD Left",
1051da177e4SLinus Torvalds /* 0x03 */ "Audigy CD Right",
1061da177e4SLinus Torvalds /* 0x04 */ "Optical IEC958 Left",
1071da177e4SLinus Torvalds /* 0x05 */ "Optical IEC958 Right",
1081da177e4SLinus Torvalds /* 0x06 */ NULL,
1091da177e4SLinus Torvalds /* 0x07 */ NULL,
1101da177e4SLinus Torvalds /* 0x08 */ "Line/Mic 2 Left",
1111da177e4SLinus Torvalds /* 0x09 */ "Line/Mic 2 Right",
1121da177e4SLinus Torvalds /* 0x0a */ "SPDIF Left",
1131da177e4SLinus Torvalds /* 0x0b */ "SPDIF Right",
1141da177e4SLinus Torvalds /* 0x0c */ "Aux2 Left",
1151da177e4SLinus Torvalds /* 0x0d */ "Aux2 Right",
1161da177e4SLinus Torvalds /* 0x0e */ NULL,
1171da177e4SLinus Torvalds /* 0x0f */ NULL
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds
120db987421SOswald Buddenhagen // Physical outputs; corresponds with the public EXTOUT_* defines.
121db987421SOswald Buddenhagen const char * const snd_emu10k1_sblive_outs[32] = {
1221da177e4SLinus Torvalds /* 0x00 */ "AC97 Left",
1231da177e4SLinus Torvalds /* 0x01 */ "AC97 Right",
1241da177e4SLinus Torvalds /* 0x02 */ "Optical IEC958 Left",
1251da177e4SLinus Torvalds /* 0x03 */ "Optical IEC958 Right",
1261da177e4SLinus Torvalds /* 0x04 */ "Center",
1271da177e4SLinus Torvalds /* 0x05 */ "LFE",
1281da177e4SLinus Torvalds /* 0x06 */ "Headphone Left",
1291da177e4SLinus Torvalds /* 0x07 */ "Headphone Right",
1301da177e4SLinus Torvalds /* 0x08 */ "Surround Left",
1311da177e4SLinus Torvalds /* 0x09 */ "Surround Right",
1321da177e4SLinus Torvalds /* 0x0a */ "PCM Capture Left",
1331da177e4SLinus Torvalds /* 0x0b */ "PCM Capture Right",
1341da177e4SLinus Torvalds /* 0x0c */ "MIC Capture",
1351da177e4SLinus Torvalds /* 0x0d */ "AC97 Surround Left",
1361da177e4SLinus Torvalds /* 0x0e */ "AC97 Surround Right",
1371da177e4SLinus Torvalds /* 0x0f */ NULL,
138db987421SOswald Buddenhagen // This is actually the FXBUS2 range; SB Live! 5.1 only.
1391da177e4SLinus Torvalds /* 0x10 */ NULL,
1401da177e4SLinus Torvalds /* 0x11 */ "Analog Center",
1411da177e4SLinus Torvalds /* 0x12 */ "Analog LFE",
1421da177e4SLinus Torvalds /* 0x13 */ NULL,
1431da177e4SLinus Torvalds /* 0x14 */ NULL,
1441da177e4SLinus Torvalds /* 0x15 */ NULL,
1451da177e4SLinus Torvalds /* 0x16 */ NULL,
1461da177e4SLinus Torvalds /* 0x17 */ NULL,
1471da177e4SLinus Torvalds /* 0x18 */ NULL,
1481da177e4SLinus Torvalds /* 0x19 */ NULL,
1491da177e4SLinus Torvalds /* 0x1a */ NULL,
1501da177e4SLinus Torvalds /* 0x1b */ NULL,
1511da177e4SLinus Torvalds /* 0x1c */ NULL,
1521da177e4SLinus Torvalds /* 0x1d */ NULL,
1531da177e4SLinus Torvalds /* 0x1e */ NULL,
1541da177e4SLinus Torvalds /* 0x1f */ NULL,
1551da177e4SLinus Torvalds };
1561da177e4SLinus Torvalds
157db987421SOswald Buddenhagen // Physical outputs; corresponds with the public A_EXTOUT_* defines.
158db987421SOswald Buddenhagen const char * const snd_emu10k1_audigy_outs[32] = {
1591da177e4SLinus Torvalds /* 0x00 */ "Digital Front Left",
1601da177e4SLinus Torvalds /* 0x01 */ "Digital Front Right",
1611da177e4SLinus Torvalds /* 0x02 */ "Digital Center",
1621da177e4SLinus Torvalds /* 0x03 */ "Digital LEF",
1631da177e4SLinus Torvalds /* 0x04 */ "Headphone Left",
1641da177e4SLinus Torvalds /* 0x05 */ "Headphone Right",
1651da177e4SLinus Torvalds /* 0x06 */ "Digital Rear Left",
1661da177e4SLinus Torvalds /* 0x07 */ "Digital Rear Right",
1671da177e4SLinus Torvalds /* 0x08 */ "Front Left",
1681da177e4SLinus Torvalds /* 0x09 */ "Front Right",
1691da177e4SLinus Torvalds /* 0x0a */ "Center",
1701da177e4SLinus Torvalds /* 0x0b */ "LFE",
1711da177e4SLinus Torvalds /* 0x0c */ NULL,
1721da177e4SLinus Torvalds /* 0x0d */ NULL,
1731da177e4SLinus Torvalds /* 0x0e */ "Rear Left",
1741da177e4SLinus Torvalds /* 0x0f */ "Rear Right",
1751da177e4SLinus Torvalds /* 0x10 */ "AC97 Front Left",
1761da177e4SLinus Torvalds /* 0x11 */ "AC97 Front Right",
177bf8b47feSColin Ian King /* 0x12 */ "ADC Capture Left",
1781da177e4SLinus Torvalds /* 0x13 */ "ADC Capture Right",
1791da177e4SLinus Torvalds /* 0x14 */ NULL,
1801da177e4SLinus Torvalds /* 0x15 */ NULL,
1811da177e4SLinus Torvalds /* 0x16 */ NULL,
1821da177e4SLinus Torvalds /* 0x17 */ NULL,
1831da177e4SLinus Torvalds /* 0x18 */ NULL,
1841da177e4SLinus Torvalds /* 0x19 */ NULL,
1851da177e4SLinus Torvalds /* 0x1a */ NULL,
1861da177e4SLinus Torvalds /* 0x1b */ NULL,
1871da177e4SLinus Torvalds /* 0x1c */ NULL,
1881da177e4SLinus Torvalds /* 0x1d */ NULL,
1891da177e4SLinus Torvalds /* 0x1e */ NULL,
1901da177e4SLinus Torvalds /* 0x1f */ NULL,
1911da177e4SLinus Torvalds };
1921da177e4SLinus Torvalds
193db987421SOswald Buddenhagen // On the SB Live! 5.1, FXBUS2[1] and FXBUS2[2] are occupied by EXTOUT_ACENTER
194db987421SOswald Buddenhagen // and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording.
195db987421SOswald Buddenhagen //
196db987421SOswald Buddenhagen // Since only 14 of the 16 EXTINs are used, this is not a big problem.
197db987421SOswald Buddenhagen // We route AC97 to FX capture 14 and 15, SPDIF_CD to FX capture 0 and 3,
198db987421SOswald Buddenhagen // and the rest of the EXTINs to the corresponding FX capture channel.
199db987421SOswald Buddenhagen // Multitrack recorders will still see the center/LFE output signal
200db987421SOswald Buddenhagen // on the second and third "input" channel.
201db987421SOswald Buddenhagen const s8 snd_emu10k1_sblive51_fxbus2_map[16] = {
202db987421SOswald Buddenhagen 2, -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1
203db987421SOswald Buddenhagen };
204db987421SOswald Buddenhagen
2051da177e4SLinus Torvalds static const u32 bass_table[41][5] = {
2061da177e4SLinus Torvalds { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
2071da177e4SLinus Torvalds { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
2081da177e4SLinus Torvalds { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
2091da177e4SLinus Torvalds { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
2101da177e4SLinus Torvalds { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
2111da177e4SLinus Torvalds { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
2121da177e4SLinus Torvalds { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
2131da177e4SLinus Torvalds { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
2141da177e4SLinus Torvalds { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
2151da177e4SLinus Torvalds { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
2161da177e4SLinus Torvalds { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
2171da177e4SLinus Torvalds { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
2181da177e4SLinus Torvalds { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
2191da177e4SLinus Torvalds { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
2201da177e4SLinus Torvalds { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
2211da177e4SLinus Torvalds { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
2221da177e4SLinus Torvalds { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
2231da177e4SLinus Torvalds { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
2241da177e4SLinus Torvalds { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
2251da177e4SLinus Torvalds { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
2261da177e4SLinus Torvalds { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
2271da177e4SLinus Torvalds { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
2281da177e4SLinus Torvalds { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
2291da177e4SLinus Torvalds { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
2301da177e4SLinus Torvalds { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
2311da177e4SLinus Torvalds { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
2321da177e4SLinus Torvalds { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
2331da177e4SLinus Torvalds { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
2341da177e4SLinus Torvalds { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
2351da177e4SLinus Torvalds { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
2361da177e4SLinus Torvalds { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
2371da177e4SLinus Torvalds { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
2381da177e4SLinus Torvalds { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
2391da177e4SLinus Torvalds { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
2401da177e4SLinus Torvalds { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
2411da177e4SLinus Torvalds { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
2421da177e4SLinus Torvalds { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
2431da177e4SLinus Torvalds { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
2441da177e4SLinus Torvalds { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
2451da177e4SLinus Torvalds { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
2461da177e4SLinus Torvalds { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
2471da177e4SLinus Torvalds };
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds static const u32 treble_table[41][5] = {
2501da177e4SLinus Torvalds { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
2511da177e4SLinus Torvalds { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
2521da177e4SLinus Torvalds { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
2531da177e4SLinus Torvalds { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
2541da177e4SLinus Torvalds { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
2551da177e4SLinus Torvalds { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
2561da177e4SLinus Torvalds { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
2571da177e4SLinus Torvalds { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
2581da177e4SLinus Torvalds { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
2591da177e4SLinus Torvalds { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
2601da177e4SLinus Torvalds { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
2611da177e4SLinus Torvalds { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
2621da177e4SLinus Torvalds { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
2631da177e4SLinus Torvalds { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
2641da177e4SLinus Torvalds { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
2651da177e4SLinus Torvalds { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
2661da177e4SLinus Torvalds { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
2671da177e4SLinus Torvalds { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
2681da177e4SLinus Torvalds { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
2691da177e4SLinus Torvalds { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
2701da177e4SLinus Torvalds { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
2711da177e4SLinus Torvalds { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
2721da177e4SLinus Torvalds { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
2731da177e4SLinus Torvalds { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
2741da177e4SLinus Torvalds { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
2751da177e4SLinus Torvalds { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
2761da177e4SLinus Torvalds { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
2771da177e4SLinus Torvalds { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
2781da177e4SLinus Torvalds { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
2791da177e4SLinus Torvalds { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
2801da177e4SLinus Torvalds { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
2811da177e4SLinus Torvalds { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
2821da177e4SLinus Torvalds { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
2831da177e4SLinus Torvalds { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
2841da177e4SLinus Torvalds { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
2851da177e4SLinus Torvalds { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
2861da177e4SLinus Torvalds { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
2871da177e4SLinus Torvalds { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
2881da177e4SLinus Torvalds { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
2891da177e4SLinus Torvalds { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
2901da177e4SLinus Torvalds { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
2911da177e4SLinus Torvalds };
2921da177e4SLinus Torvalds
2937012b2daSJames Courtier-Dutton /* dB gain = (float) 20 * log10( float(db_table_value) / 0x8000000 ) */
2941da177e4SLinus Torvalds static const u32 db_table[101] = {
2951da177e4SLinus Torvalds 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
2961da177e4SLinus Torvalds 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
2971da177e4SLinus Torvalds 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
2981da177e4SLinus Torvalds 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
2991da177e4SLinus Torvalds 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
3001da177e4SLinus Torvalds 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
3011da177e4SLinus Torvalds 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
3021da177e4SLinus Torvalds 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
3031da177e4SLinus Torvalds 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
3041da177e4SLinus Torvalds 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
3051da177e4SLinus Torvalds 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
3061da177e4SLinus Torvalds 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
3071da177e4SLinus Torvalds 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
3081da177e4SLinus Torvalds 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
3091da177e4SLinus Torvalds 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
3101da177e4SLinus Torvalds 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
3111da177e4SLinus Torvalds 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
3121da177e4SLinus Torvalds 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
3131da177e4SLinus Torvalds 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
3141da177e4SLinus Torvalds 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
3151da177e4SLinus Torvalds 0x7fffffff,
3161da177e4SLinus Torvalds };
3171da177e4SLinus Torvalds
31831508f83SJames Courtier-Dutton /* EMU10k1/EMU10k2 DSP control db gain */
3190cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_emu10k1_db_scale1, -4000, 40, 1);
3204daf7a0cSClemens Ladisch static const DECLARE_TLV_DB_LINEAR(snd_emu10k1_db_linear, TLV_DB_GAIN_MUTE, 0);
32131508f83SJames Courtier-Dutton
322bfe9fc8aSRaymond Yau /* EMU10K1 bass/treble db gain */
323bfe9fc8aSRaymond Yau static const DECLARE_TLV_DB_SCALE(snd_emu10k1_bass_treble_db_scale, -1200, 60, 0);
324bfe9fc8aSRaymond Yau
3251da177e4SLinus Torvalds static const u32 onoff_table[2] = {
3261da177e4SLinus Torvalds 0x00000000, 0x00000001
3271da177e4SLinus Torvalds };
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds /*
3301da177e4SLinus Torvalds * controls
3311da177e4SLinus Torvalds */
3321da177e4SLinus Torvalds
snd_emu10k1_gpr_ctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)333eb4698f3STakashi Iwai static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
3341da177e4SLinus Torvalds {
335eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl =
336eb4698f3STakashi Iwai (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
3371da177e4SLinus Torvalds
3381da177e4SLinus Torvalds if (ctl->min == 0 && ctl->max == 1)
3391da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3401da177e4SLinus Torvalds else
3411da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3421da177e4SLinus Torvalds uinfo->count = ctl->vcount;
3431da177e4SLinus Torvalds uinfo->value.integer.min = ctl->min;
3441da177e4SLinus Torvalds uinfo->value.integer.max = ctl->max;
3451da177e4SLinus Torvalds return 0;
3461da177e4SLinus Torvalds }
3471da177e4SLinus Torvalds
snd_emu10k1_gpr_ctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)348eb4698f3STakashi Iwai static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3491da177e4SLinus Torvalds {
350eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl =
351eb4698f3STakashi Iwai (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
3521da177e4SLinus Torvalds unsigned int i;
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds for (i = 0; i < ctl->vcount; i++)
3551da177e4SLinus Torvalds ucontrol->value.integer.value[i] = ctl->value[i];
3561da177e4SLinus Torvalds return 0;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
snd_emu10k1_gpr_ctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)359eb4698f3STakashi Iwai static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3601da177e4SLinus Torvalds {
361eb4698f3STakashi Iwai struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
362eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl =
363eb4698f3STakashi Iwai (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value;
3641298bc97SOswald Buddenhagen int nval, val;
3651da177e4SLinus Torvalds unsigned int i, j;
3661da177e4SLinus Torvalds int change = 0;
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds for (i = 0; i < ctl->vcount; i++) {
3691da177e4SLinus Torvalds nval = ucontrol->value.integer.value[i];
3701da177e4SLinus Torvalds if (nval < ctl->min)
3711da177e4SLinus Torvalds nval = ctl->min;
3721da177e4SLinus Torvalds if (nval > ctl->max)
3731da177e4SLinus Torvalds nval = ctl->max;
3741da177e4SLinus Torvalds if (nval != ctl->value[i])
3751da177e4SLinus Torvalds change = 1;
3761da177e4SLinus Torvalds val = ctl->value[i] = nval;
3771da177e4SLinus Torvalds switch (ctl->translation) {
3781da177e4SLinus Torvalds case EMU10K1_GPR_TRANSLATION_NONE:
3791da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val);
3801da177e4SLinus Torvalds break;
3811298bc97SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_NEGATE:
3821298bc97SOswald Buddenhagen snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, ~val);
3831298bc97SOswald Buddenhagen break;
3841da177e4SLinus Torvalds case EMU10K1_GPR_TRANSLATION_TABLE100:
3851da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]);
3861da177e4SLinus Torvalds break;
3871298bc97SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
3881298bc97SOswald Buddenhagen snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0,
3891298bc97SOswald Buddenhagen val == 100 ? 0x80000000 : -(int)db_table[val]);
3901298bc97SOswald Buddenhagen break;
3911da177e4SLinus Torvalds case EMU10K1_GPR_TRANSLATION_BASS:
3927c22f1aaSTakashi Iwai if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
3937c22f1aaSTakashi Iwai change = -EIO;
3947c22f1aaSTakashi Iwai goto __error;
3957c22f1aaSTakashi Iwai }
3961da177e4SLinus Torvalds for (j = 0; j < 5; j++)
3971da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]);
3981da177e4SLinus Torvalds break;
3991da177e4SLinus Torvalds case EMU10K1_GPR_TRANSLATION_TREBLE:
4007c22f1aaSTakashi Iwai if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) {
4017c22f1aaSTakashi Iwai change = -EIO;
4027c22f1aaSTakashi Iwai goto __error;
4037c22f1aaSTakashi Iwai }
4041da177e4SLinus Torvalds for (j = 0; j < 5; j++)
4051da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]);
4061da177e4SLinus Torvalds break;
4071da177e4SLinus Torvalds case EMU10K1_GPR_TRANSLATION_ONOFF:
4081da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]);
4091da177e4SLinus Torvalds break;
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds __error:
4131da177e4SLinus Torvalds return change;
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds
4161da177e4SLinus Torvalds /*
4171da177e4SLinus Torvalds * Interrupt handler
4181da177e4SLinus Torvalds */
4191da177e4SLinus Torvalds
snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 * emu)420eb4698f3STakashi Iwai static void snd_emu10k1_fx8010_interrupt(struct snd_emu10k1 *emu)
4211da177e4SLinus Torvalds {
422eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_irq *irq, *nirq;
4231da177e4SLinus Torvalds
4241da177e4SLinus Torvalds irq = emu->fx8010.irq_handlers;
4251da177e4SLinus Torvalds while (irq) {
4261da177e4SLinus Torvalds nirq = irq->next; /* irq ptr can be removed from list */
4271da177e4SLinus Torvalds if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) {
4281da177e4SLinus Torvalds if (irq->handler)
4291da177e4SLinus Torvalds irq->handler(emu, irq->private_data);
4301da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1);
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds irq = nirq;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds
snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 * emu,snd_fx8010_irq_handler_t * handler,unsigned char gpr_running,void * private_data,struct snd_emu10k1_fx8010_irq * irq)436eb4698f3STakashi Iwai int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu,
4371da177e4SLinus Torvalds snd_fx8010_irq_handler_t *handler,
4381da177e4SLinus Torvalds unsigned char gpr_running,
4391da177e4SLinus Torvalds void *private_data,
440057666b6STakashi Iwai struct snd_emu10k1_fx8010_irq *irq)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds unsigned long flags;
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds irq->handler = handler;
4451da177e4SLinus Torvalds irq->gpr_running = gpr_running;
4461da177e4SLinus Torvalds irq->private_data = private_data;
4471da177e4SLinus Torvalds irq->next = NULL;
4481da177e4SLinus Torvalds spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
4491da177e4SLinus Torvalds if (emu->fx8010.irq_handlers == NULL) {
4501da177e4SLinus Torvalds emu->fx8010.irq_handlers = irq;
4511da177e4SLinus Torvalds emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt;
4521da177e4SLinus Torvalds snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE);
4531da177e4SLinus Torvalds } else {
4541da177e4SLinus Torvalds irq->next = emu->fx8010.irq_handlers;
4551da177e4SLinus Torvalds emu->fx8010.irq_handlers = irq;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
4581da177e4SLinus Torvalds return 0;
4591da177e4SLinus Torvalds }
4601da177e4SLinus Torvalds
snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_irq * irq)461eb4698f3STakashi Iwai int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu,
462eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_irq *irq)
4631da177e4SLinus Torvalds {
464eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_irq *tmp;
4651da177e4SLinus Torvalds unsigned long flags;
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds spin_lock_irqsave(&emu->fx8010.irq_lock, flags);
46812bda107STakashi Iwai tmp = emu->fx8010.irq_handlers;
46912bda107STakashi Iwai if (tmp == irq) {
4701da177e4SLinus Torvalds emu->fx8010.irq_handlers = tmp->next;
4711da177e4SLinus Torvalds if (emu->fx8010.irq_handlers == NULL) {
4721da177e4SLinus Torvalds snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE);
4731da177e4SLinus Torvalds emu->dsp_interrupt = NULL;
4741da177e4SLinus Torvalds }
4751da177e4SLinus Torvalds } else {
4761da177e4SLinus Torvalds while (tmp && tmp->next != irq)
4771da177e4SLinus Torvalds tmp = tmp->next;
4781da177e4SLinus Torvalds if (tmp)
4791da177e4SLinus Torvalds tmp->next = tmp->next->next;
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags);
4821da177e4SLinus Torvalds return 0;
4831da177e4SLinus Torvalds }
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds /*************************************************************************
4861da177e4SLinus Torvalds * EMU10K1 effect manager
4871da177e4SLinus Torvalds *************************************************************************/
4881da177e4SLinus Torvalds
snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code * icode,unsigned int * ptr,u32 op,u32 r,u32 a,u32 x,u32 y)489eb4698f3STakashi Iwai static void snd_emu10k1_write_op(struct snd_emu10k1_fx8010_code *icode,
490eb4698f3STakashi Iwai unsigned int *ptr,
4911da177e4SLinus Torvalds u32 op, u32 r, u32 a, u32 x, u32 y)
4921da177e4SLinus Torvalds {
4931da177e4SLinus Torvalds u_int32_t *code;
494da3cec35STakashi Iwai if (snd_BUG_ON(*ptr >= 512))
495da3cec35STakashi Iwai return;
49681b45090STakashi Iwai code = icode->code + (*ptr) * 2;
4971da177e4SLinus Torvalds set_bit(*ptr, icode->code_valid);
4981da177e4SLinus Torvalds code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
4991da177e4SLinus Torvalds code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
5001da177e4SLinus Torvalds (*ptr)++;
5011da177e4SLinus Torvalds }
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds #define OP(icode, ptr, op, r, a, x, y) \
5041da177e4SLinus Torvalds snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)
5051da177e4SLinus Torvalds
snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code * icode,unsigned int * ptr,u32 op,u32 r,u32 a,u32 x,u32 y)506eb4698f3STakashi Iwai static void snd_emu10k1_audigy_write_op(struct snd_emu10k1_fx8010_code *icode,
507eb4698f3STakashi Iwai unsigned int *ptr,
5081da177e4SLinus Torvalds u32 op, u32 r, u32 a, u32 x, u32 y)
5091da177e4SLinus Torvalds {
5101da177e4SLinus Torvalds u_int32_t *code;
511da3cec35STakashi Iwai if (snd_BUG_ON(*ptr >= 1024))
512da3cec35STakashi Iwai return;
51381b45090STakashi Iwai code = icode->code + (*ptr) * 2;
5141da177e4SLinus Torvalds set_bit(*ptr, icode->code_valid);
5151da177e4SLinus Torvalds code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
5161da177e4SLinus Torvalds code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
5171da177e4SLinus Torvalds (*ptr)++;
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds
5201da177e4SLinus Torvalds #define A_OP(icode, ptr, op, r, a, x, y) \
5211da177e4SLinus Torvalds snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)
5221da177e4SLinus Torvalds
snd_emu10k1_efx_write(struct snd_emu10k1 * emu,unsigned int pc,unsigned int data)523eb4698f3STakashi Iwai static void snd_emu10k1_efx_write(struct snd_emu10k1 *emu, unsigned int pc, unsigned int data)
5241da177e4SLinus Torvalds {
5251da177e4SLinus Torvalds pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
5261da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, pc, 0, data);
5271da177e4SLinus Torvalds }
5281da177e4SLinus Torvalds
snd_emu10k1_efx_read(struct snd_emu10k1 * emu,unsigned int pc)529eb4698f3STakashi Iwai unsigned int snd_emu10k1_efx_read(struct snd_emu10k1 *emu, unsigned int pc)
5301da177e4SLinus Torvalds {
5311da177e4SLinus Torvalds pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE;
5321da177e4SLinus Torvalds return snd_emu10k1_ptr_read(emu, pc, 0);
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds
snd_emu10k1_gpr_poke(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)535eb4698f3STakashi Iwai static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
536d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
537d42fe63dSTakashi Iwai bool in_kernel)
5381da177e4SLinus Torvalds {
5391da177e4SLinus Torvalds int gpr;
5401da177e4SLinus Torvalds u32 val;
5411da177e4SLinus Torvalds
5421da177e4SLinus Torvalds for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
5431da177e4SLinus Torvalds if (!test_bit(gpr, icode->gpr_valid))
5441da177e4SLinus Torvalds continue;
545d42fe63dSTakashi Iwai if (in_kernel)
54681b45090STakashi Iwai val = icode->gpr_map[gpr];
54781b45090STakashi Iwai else if (get_user(val, (__user u32 *)&icode->gpr_map[gpr]))
5481da177e4SLinus Torvalds return -EFAULT;
5491da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
5501da177e4SLinus Torvalds }
5511da177e4SLinus Torvalds return 0;
5521da177e4SLinus Torvalds }
5531da177e4SLinus Torvalds
snd_emu10k1_gpr_peek(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode)554eb4698f3STakashi Iwai static int snd_emu10k1_gpr_peek(struct snd_emu10k1 *emu,
555eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode)
5561da177e4SLinus Torvalds {
5571da177e4SLinus Torvalds int gpr;
5581da177e4SLinus Torvalds u32 val;
5591da177e4SLinus Torvalds
5601da177e4SLinus Torvalds for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) {
5611da177e4SLinus Torvalds set_bit(gpr, icode->gpr_valid);
5621da177e4SLinus Torvalds val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
56381b45090STakashi Iwai if (put_user(val, (__user u32 *)&icode->gpr_map[gpr]))
5641da177e4SLinus Torvalds return -EFAULT;
5651da177e4SLinus Torvalds }
5661da177e4SLinus Torvalds return 0;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds
snd_emu10k1_tram_poke(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)569eb4698f3STakashi Iwai static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
570d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
571d42fe63dSTakashi Iwai bool in_kernel)
5721da177e4SLinus Torvalds {
5731da177e4SLinus Torvalds int tram;
5741da177e4SLinus Torvalds u32 addr, val;
5751da177e4SLinus Torvalds
5761da177e4SLinus Torvalds for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
5771da177e4SLinus Torvalds if (!test_bit(tram, icode->tram_valid))
5781da177e4SLinus Torvalds continue;
579d42fe63dSTakashi Iwai if (in_kernel) {
58081b45090STakashi Iwai val = icode->tram_data_map[tram];
58181b45090STakashi Iwai addr = icode->tram_addr_map[tram];
582d42fe63dSTakashi Iwai } else {
58381b45090STakashi Iwai if (get_user(val, (__user __u32 *)&icode->tram_data_map[tram]) ||
58481b45090STakashi Iwai get_user(addr, (__user __u32 *)&icode->tram_addr_map[tram]))
5851da177e4SLinus Torvalds return -EFAULT;
586d42fe63dSTakashi Iwai }
5871da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val);
5881da177e4SLinus Torvalds if (!emu->audigy) {
5891da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr);
5901da177e4SLinus Torvalds } else {
5911da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12);
5921da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20);
5931da177e4SLinus Torvalds }
5941da177e4SLinus Torvalds }
5951da177e4SLinus Torvalds return 0;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds
snd_emu10k1_tram_peek(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode)598eb4698f3STakashi Iwai static int snd_emu10k1_tram_peek(struct snd_emu10k1 *emu,
599eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode)
6001da177e4SLinus Torvalds {
6011da177e4SLinus Torvalds int tram;
6021da177e4SLinus Torvalds u32 val, addr;
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
6051da177e4SLinus Torvalds for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) {
6061da177e4SLinus Torvalds set_bit(tram, icode->tram_valid);
6071da177e4SLinus Torvalds val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
6081da177e4SLinus Torvalds if (!emu->audigy) {
6091da177e4SLinus Torvalds addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
6101da177e4SLinus Torvalds } else {
6111da177e4SLinus Torvalds addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12;
6121da177e4SLinus Torvalds addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20;
6131da177e4SLinus Torvalds }
61481b45090STakashi Iwai if (put_user(val, (__user u32 *)&icode->tram_data_map[tram]) ||
61581b45090STakashi Iwai put_user(addr, (__user u32 *)&icode->tram_addr_map[tram]))
6161da177e4SLinus Torvalds return -EFAULT;
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds return 0;
6191da177e4SLinus Torvalds }
6201da177e4SLinus Torvalds
snd_emu10k1_code_poke(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)621eb4698f3STakashi Iwai static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
622d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
623d42fe63dSTakashi Iwai bool in_kernel)
6241da177e4SLinus Torvalds {
6251da177e4SLinus Torvalds u32 pc, lo, hi;
6261da177e4SLinus Torvalds
6271da177e4SLinus Torvalds for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
6281da177e4SLinus Torvalds if (!test_bit(pc / 2, icode->code_valid))
6291da177e4SLinus Torvalds continue;
630d42fe63dSTakashi Iwai if (in_kernel) {
63181b45090STakashi Iwai lo = icode->code[pc + 0];
63281b45090STakashi Iwai hi = icode->code[pc + 1];
633d42fe63dSTakashi Iwai } else {
63481b45090STakashi Iwai if (get_user(lo, (__user u32 *)&icode->code[pc + 0]) ||
63581b45090STakashi Iwai get_user(hi, (__user u32 *)&icode->code[pc + 1]))
6361da177e4SLinus Torvalds return -EFAULT;
637d42fe63dSTakashi Iwai }
6381da177e4SLinus Torvalds snd_emu10k1_efx_write(emu, pc + 0, lo);
6391da177e4SLinus Torvalds snd_emu10k1_efx_write(emu, pc + 1, hi);
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds return 0;
6421da177e4SLinus Torvalds }
6431da177e4SLinus Torvalds
snd_emu10k1_code_peek(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode)644eb4698f3STakashi Iwai static int snd_emu10k1_code_peek(struct snd_emu10k1 *emu,
645eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode)
6461da177e4SLinus Torvalds {
6471da177e4SLinus Torvalds u32 pc;
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds memset(icode->code_valid, 0, sizeof(icode->code_valid));
6501da177e4SLinus Torvalds for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) {
6511da177e4SLinus Torvalds set_bit(pc / 2, icode->code_valid);
65281b45090STakashi Iwai if (put_user(snd_emu10k1_efx_read(emu, pc + 0),
65381b45090STakashi Iwai (__user u32 *)&icode->code[pc + 0]))
6541da177e4SLinus Torvalds return -EFAULT;
65581b45090STakashi Iwai if (put_user(snd_emu10k1_efx_read(emu, pc + 1),
65681b45090STakashi Iwai (__user u32 *)&icode->code[pc + 1]))
6571da177e4SLinus Torvalds return -EFAULT;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds return 0;
6601da177e4SLinus Torvalds }
6611da177e4SLinus Torvalds
662eb4698f3STakashi Iwai static struct snd_emu10k1_fx8010_ctl *
snd_emu10k1_look_for_ctl(struct snd_emu10k1 * emu,struct emu10k1_ctl_elem_id * _id)66381b45090STakashi Iwai snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu,
66481b45090STakashi Iwai struct emu10k1_ctl_elem_id *_id)
6651da177e4SLinus Torvalds {
66681b45090STakashi Iwai struct snd_ctl_elem_id *id = (struct snd_ctl_elem_id *)_id;
667eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl;
668eb4698f3STakashi Iwai struct snd_kcontrol *kcontrol;
6691da177e4SLinus Torvalds
670c2d7051eSMatthias Kaehlcke list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
6711da177e4SLinus Torvalds kcontrol = ctl->kcontrol;
6721da177e4SLinus Torvalds if (kcontrol->id.iface == id->iface &&
673e922da40SOswald Buddenhagen kcontrol->id.index == id->index &&
674e922da40SOswald Buddenhagen !strcmp(kcontrol->id.name, id->name))
6751da177e4SLinus Torvalds return ctl;
6761da177e4SLinus Torvalds }
6771da177e4SLinus Torvalds return NULL;
6781da177e4SLinus Torvalds }
6791da177e4SLinus Torvalds
680f7ba7fc6STakashi Iwai #define MAX_TLV_SIZE 256
681f7ba7fc6STakashi Iwai
copy_tlv(const unsigned int __user * _tlv,bool in_kernel)682d42fe63dSTakashi Iwai static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
683f7ba7fc6STakashi Iwai {
684f7ba7fc6STakashi Iwai unsigned int data[2];
685f7ba7fc6STakashi Iwai unsigned int *tlv;
686f7ba7fc6STakashi Iwai
687f7ba7fc6STakashi Iwai if (!_tlv)
688f7ba7fc6STakashi Iwai return NULL;
689d42fe63dSTakashi Iwai if (in_kernel)
69063623646STakashi Iwai memcpy(data, (__force void *)_tlv, sizeof(data));
691d42fe63dSTakashi Iwai else if (copy_from_user(data, _tlv, sizeof(data)))
692f7ba7fc6STakashi Iwai return NULL;
693f7ba7fc6STakashi Iwai if (data[1] >= MAX_TLV_SIZE)
694f7ba7fc6STakashi Iwai return NULL;
6956735e572STakashi Iwai tlv = kmalloc(data[1] + sizeof(data), GFP_KERNEL);
696f7ba7fc6STakashi Iwai if (!tlv)
697f7ba7fc6STakashi Iwai return NULL;
698f7ba7fc6STakashi Iwai memcpy(tlv, data, sizeof(data));
699d42fe63dSTakashi Iwai if (in_kernel) {
70063623646STakashi Iwai memcpy(tlv + 2, (__force void *)(_tlv + 2), data[1]);
701d42fe63dSTakashi Iwai } else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
702f7ba7fc6STakashi Iwai kfree(tlv);
703f7ba7fc6STakashi Iwai return NULL;
704f7ba7fc6STakashi Iwai }
705f7ba7fc6STakashi Iwai return tlv;
706f7ba7fc6STakashi Iwai }
707f7ba7fc6STakashi Iwai
copy_gctl(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_control_gpr * dst,struct snd_emu10k1_fx8010_control_gpr * src,int idx,bool in_kernel)708f7ba7fc6STakashi Iwai static int copy_gctl(struct snd_emu10k1 *emu,
70981b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *dst,
71081b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *src,
711d42fe63dSTakashi Iwai int idx, bool in_kernel)
712f7ba7fc6STakashi Iwai {
71381b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr __user *_src;
71481b45090STakashi Iwai struct snd_emu10k1_fx8010_control_old_gpr *octl;
71581b45090STakashi Iwai struct snd_emu10k1_fx8010_control_old_gpr __user *_octl;
716f7ba7fc6STakashi Iwai
71781b45090STakashi Iwai _src = (struct snd_emu10k1_fx8010_control_gpr __user *)src;
7180b36f2bdSTakashi Iwai if (emu->support_tlv) {
7190b36f2bdSTakashi Iwai if (in_kernel)
72081b45090STakashi Iwai *dst = src[idx];
72181b45090STakashi Iwai else if (copy_from_user(dst, &_src[idx], sizeof(*src)))
7220b36f2bdSTakashi Iwai return -EFAULT;
7230b36f2bdSTakashi Iwai return 0;
7240b36f2bdSTakashi Iwai }
7250b36f2bdSTakashi Iwai
72681b45090STakashi Iwai octl = (struct snd_emu10k1_fx8010_control_old_gpr *)src;
72781b45090STakashi Iwai _octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)octl;
7280b36f2bdSTakashi Iwai if (in_kernel)
72981b45090STakashi Iwai memcpy(dst, &octl[idx], sizeof(*octl));
73081b45090STakashi Iwai else if (copy_from_user(dst, &_octl[idx], sizeof(*octl)))
731f7ba7fc6STakashi Iwai return -EFAULT;
73281b45090STakashi Iwai dst->tlv = NULL;
733f7ba7fc6STakashi Iwai return 0;
734f7ba7fc6STakashi Iwai }
735f7ba7fc6STakashi Iwai
copy_gctl_to_user(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_control_gpr * dst,struct snd_emu10k1_fx8010_control_gpr * src,int idx)736f7ba7fc6STakashi Iwai static int copy_gctl_to_user(struct snd_emu10k1 *emu,
73781b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *dst,
73881b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *src,
739f7ba7fc6STakashi Iwai int idx)
740f7ba7fc6STakashi Iwai {
74181b45090STakashi Iwai struct snd_emu10k1_fx8010_control_gpr __user *_dst;
742f7ba7fc6STakashi Iwai struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
743f7ba7fc6STakashi Iwai
74481b45090STakashi Iwai _dst = (struct snd_emu10k1_fx8010_control_gpr __user *)dst;
745f7ba7fc6STakashi Iwai if (emu->support_tlv)
74681b45090STakashi Iwai return copy_to_user(&_dst[idx], src, sizeof(*src));
747f7ba7fc6STakashi Iwai
74881b45090STakashi Iwai octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)dst;
74981b45090STakashi Iwai return copy_to_user(&octl[idx], src, sizeof(*octl));
75081b45090STakashi Iwai }
75181b45090STakashi Iwai
copy_ctl_elem_id(const struct emu10k1_ctl_elem_id * list,int i,struct emu10k1_ctl_elem_id * ret,bool in_kernel)75281b45090STakashi Iwai static int copy_ctl_elem_id(const struct emu10k1_ctl_elem_id *list, int i,
75381b45090STakashi Iwai struct emu10k1_ctl_elem_id *ret, bool in_kernel)
75481b45090STakashi Iwai {
75581b45090STakashi Iwai struct emu10k1_ctl_elem_id __user *_id =
75681b45090STakashi Iwai (struct emu10k1_ctl_elem_id __user *)&list[i];
75781b45090STakashi Iwai
75881b45090STakashi Iwai if (in_kernel)
75981b45090STakashi Iwai *ret = list[i];
76081b45090STakashi Iwai else if (copy_from_user(ret, _id, sizeof(*ret)))
76181b45090STakashi Iwai return -EFAULT;
76281b45090STakashi Iwai return 0;
763f7ba7fc6STakashi Iwai }
764f7ba7fc6STakashi Iwai
snd_emu10k1_verify_controls(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)765eb4698f3STakashi Iwai static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
766d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
767d42fe63dSTakashi Iwai bool in_kernel)
7681da177e4SLinus Torvalds {
7691da177e4SLinus Torvalds unsigned int i;
7702e468867STakashi Iwai struct emu10k1_ctl_elem_id id;
771eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *gctl;
77281b45090STakashi Iwai struct snd_ctl_elem_id *gctl_id;
7731da177e4SLinus Torvalds int err;
7741da177e4SLinus Torvalds
77581b45090STakashi Iwai for (i = 0; i < icode->gpr_del_control_count; i++) {
77681b45090STakashi Iwai err = copy_ctl_elem_id(icode->gpr_del_controls, i, &id,
77781b45090STakashi Iwai in_kernel);
77881b45090STakashi Iwai if (err < 0)
77981b45090STakashi Iwai return err;
7801da177e4SLinus Torvalds if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
7811da177e4SLinus Torvalds return -ENOENT;
7821da177e4SLinus Torvalds }
7831da177e4SLinus Torvalds gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
7841da177e4SLinus Torvalds if (! gctl)
7851da177e4SLinus Torvalds return -ENOMEM;
7861da177e4SLinus Torvalds err = 0;
787f7ba7fc6STakashi Iwai for (i = 0; i < icode->gpr_add_control_count; i++) {
788d42fe63dSTakashi Iwai if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
789d42fe63dSTakashi Iwai in_kernel)) {
7901da177e4SLinus Torvalds err = -EFAULT;
7911da177e4SLinus Torvalds goto __error;
7921da177e4SLinus Torvalds }
7931da177e4SLinus Torvalds if (snd_emu10k1_look_for_ctl(emu, &gctl->id))
7941da177e4SLinus Torvalds continue;
79581b45090STakashi Iwai gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
79681b45090STakashi Iwai if (snd_ctl_find_id(emu->card, gctl_id)) {
7971da177e4SLinus Torvalds err = -EEXIST;
7981da177e4SLinus Torvalds goto __error;
7991da177e4SLinus Torvalds }
80081b45090STakashi Iwai if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
80181b45090STakashi Iwai gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
8021da177e4SLinus Torvalds err = -EINVAL;
8031da177e4SLinus Torvalds goto __error;
8041da177e4SLinus Torvalds }
8051a38ae57SOswald Buddenhagen switch (gctl->translation) {
8061a38ae57SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_NONE:
8071298bc97SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_NEGATE:
8081a38ae57SOswald Buddenhagen break;
8091a38ae57SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_TABLE100:
8101298bc97SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_NEG_TABLE100:
8111a38ae57SOswald Buddenhagen if (gctl->min != 0 || gctl->max != 100) {
8121a38ae57SOswald Buddenhagen err = -EINVAL;
8131a38ae57SOswald Buddenhagen goto __error;
8141a38ae57SOswald Buddenhagen }
8151a38ae57SOswald Buddenhagen break;
8161a38ae57SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_BASS:
8171a38ae57SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_TREBLE:
8181a38ae57SOswald Buddenhagen if (gctl->min != 0 || gctl->max != 40) {
8191a38ae57SOswald Buddenhagen err = -EINVAL;
8201a38ae57SOswald Buddenhagen goto __error;
8211a38ae57SOswald Buddenhagen }
8221a38ae57SOswald Buddenhagen break;
8231a38ae57SOswald Buddenhagen case EMU10K1_GPR_TRANSLATION_ONOFF:
8241a38ae57SOswald Buddenhagen if (gctl->min != 0 || gctl->max != 1) {
8251a38ae57SOswald Buddenhagen err = -EINVAL;
8261a38ae57SOswald Buddenhagen goto __error;
8271a38ae57SOswald Buddenhagen }
8281a38ae57SOswald Buddenhagen break;
8291a38ae57SOswald Buddenhagen default:
8301a38ae57SOswald Buddenhagen err = -EINVAL;
8311a38ae57SOswald Buddenhagen goto __error;
8321a38ae57SOswald Buddenhagen }
8331da177e4SLinus Torvalds }
834f7ba7fc6STakashi Iwai for (i = 0; i < icode->gpr_list_control_count; i++) {
8351da177e4SLinus Torvalds /* FIXME: we need to check the WRITE access */
836d42fe63dSTakashi Iwai if (copy_gctl(emu, gctl, icode->gpr_list_controls, i,
837d42fe63dSTakashi Iwai in_kernel)) {
8381da177e4SLinus Torvalds err = -EFAULT;
8391da177e4SLinus Torvalds goto __error;
8401da177e4SLinus Torvalds }
8411da177e4SLinus Torvalds }
8421da177e4SLinus Torvalds __error:
8431da177e4SLinus Torvalds kfree(gctl);
8441da177e4SLinus Torvalds return err;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds
snd_emu10k1_ctl_private_free(struct snd_kcontrol * kctl)847eb4698f3STakashi Iwai static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
8481da177e4SLinus Torvalds {
849eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl;
8501da177e4SLinus Torvalds
851eb4698f3STakashi Iwai ctl = (struct snd_emu10k1_fx8010_ctl *) kctl->private_value;
8521da177e4SLinus Torvalds kctl->private_value = 0;
8531da177e4SLinus Torvalds list_del(&ctl->list);
8541da177e4SLinus Torvalds kfree(ctl);
855f7ba7fc6STakashi Iwai kfree(kctl->tlv.p);
8561da177e4SLinus Torvalds }
8571da177e4SLinus Torvalds
snd_emu10k1_add_controls(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)858eb4698f3STakashi Iwai static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
859d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
860d42fe63dSTakashi Iwai bool in_kernel)
8611da177e4SLinus Torvalds {
8621da177e4SLinus Torvalds unsigned int i, j;
863eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *gctl;
86481b45090STakashi Iwai struct snd_ctl_elem_id *gctl_id;
865eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
866eb4698f3STakashi Iwai struct snd_kcontrol_new knew;
867eb4698f3STakashi Iwai struct snd_kcontrol *kctl;
868eb4698f3STakashi Iwai struct snd_ctl_elem_value *val;
8691da177e4SLinus Torvalds int err = 0;
8701da177e4SLinus Torvalds
871eb4698f3STakashi Iwai val = kmalloc(sizeof(*val), GFP_KERNEL);
8721da177e4SLinus Torvalds gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
8731da177e4SLinus Torvalds nctl = kmalloc(sizeof(*nctl), GFP_KERNEL);
8741da177e4SLinus Torvalds if (!val || !gctl || !nctl) {
8751da177e4SLinus Torvalds err = -ENOMEM;
8761da177e4SLinus Torvalds goto __error;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds
879f7ba7fc6STakashi Iwai for (i = 0; i < icode->gpr_add_control_count; i++) {
880d42fe63dSTakashi Iwai if (copy_gctl(emu, gctl, icode->gpr_add_controls, i,
881d42fe63dSTakashi Iwai in_kernel)) {
8821da177e4SLinus Torvalds err = -EFAULT;
8831da177e4SLinus Torvalds goto __error;
8841da177e4SLinus Torvalds }
88581b45090STakashi Iwai gctl_id = (struct snd_ctl_elem_id *)&gctl->id;
88681b45090STakashi Iwai if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER &&
88781b45090STakashi Iwai gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) {
8887c22f1aaSTakashi Iwai err = -EINVAL;
8897c22f1aaSTakashi Iwai goto __error;
8907c22f1aaSTakashi Iwai }
89181b45090STakashi Iwai if (!*gctl_id->name) {
8927c22f1aaSTakashi Iwai err = -EINVAL;
8937c22f1aaSTakashi Iwai goto __error;
8947c22f1aaSTakashi Iwai }
8951da177e4SLinus Torvalds ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id);
8961da177e4SLinus Torvalds memset(&knew, 0, sizeof(knew));
89781b45090STakashi Iwai knew.iface = gctl_id->iface;
89881b45090STakashi Iwai knew.name = gctl_id->name;
89981b45090STakashi Iwai knew.index = gctl_id->index;
90081b45090STakashi Iwai knew.device = gctl_id->device;
90181b45090STakashi Iwai knew.subdevice = gctl_id->subdevice;
9021da177e4SLinus Torvalds knew.info = snd_emu10k1_gpr_ctl_info;
90381b45090STakashi Iwai knew.tlv.p = copy_tlv((const unsigned int __user *)gctl->tlv, in_kernel);
904f7ba7fc6STakashi Iwai if (knew.tlv.p)
90531508f83SJames Courtier-Dutton knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
90631508f83SJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ;
9071da177e4SLinus Torvalds knew.get = snd_emu10k1_gpr_ctl_get;
9081da177e4SLinus Torvalds knew.put = snd_emu10k1_gpr_ctl_put;
9091da177e4SLinus Torvalds memset(nctl, 0, sizeof(*nctl));
9101da177e4SLinus Torvalds nctl->vcount = gctl->vcount;
9111da177e4SLinus Torvalds nctl->count = gctl->count;
9121da177e4SLinus Torvalds for (j = 0; j < 32; j++) {
9131da177e4SLinus Torvalds nctl->gpr[j] = gctl->gpr[j];
9141da177e4SLinus Torvalds nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */
9151da177e4SLinus Torvalds val->value.integer.value[j] = gctl->value[j];
9161da177e4SLinus Torvalds }
9171da177e4SLinus Torvalds nctl->min = gctl->min;
9181da177e4SLinus Torvalds nctl->max = gctl->max;
9191da177e4SLinus Torvalds nctl->translation = gctl->translation;
9201da177e4SLinus Torvalds if (ctl == NULL) {
921eb4698f3STakashi Iwai ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
9221da177e4SLinus Torvalds if (ctl == NULL) {
9231da177e4SLinus Torvalds err = -ENOMEM;
924f7ba7fc6STakashi Iwai kfree(knew.tlv.p);
9251da177e4SLinus Torvalds goto __error;
9261da177e4SLinus Torvalds }
9271da177e4SLinus Torvalds knew.private_value = (unsigned long)ctl;
9281da177e4SLinus Torvalds *ctl = *nctl;
92912bda107STakashi Iwai kctl = snd_ctl_new1(&knew, emu);
93012bda107STakashi Iwai err = snd_ctl_add(emu->card, kctl);
93112bda107STakashi Iwai if (err < 0) {
9321da177e4SLinus Torvalds kfree(ctl);
933f7ba7fc6STakashi Iwai kfree(knew.tlv.p);
9341da177e4SLinus Torvalds goto __error;
9351da177e4SLinus Torvalds }
9361da177e4SLinus Torvalds kctl->private_free = snd_emu10k1_ctl_private_free;
9371da177e4SLinus Torvalds ctl->kcontrol = kctl;
9381da177e4SLinus Torvalds list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl);
9391da177e4SLinus Torvalds } else {
9401da177e4SLinus Torvalds /* overwrite */
9411da177e4SLinus Torvalds nctl->list = ctl->list;
9421da177e4SLinus Torvalds nctl->kcontrol = ctl->kcontrol;
9431da177e4SLinus Torvalds *ctl = *nctl;
9441da177e4SLinus Torvalds snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE |
9451da177e4SLinus Torvalds SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id);
9461da177e4SLinus Torvalds }
9471da177e4SLinus Torvalds snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val);
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds __error:
9501da177e4SLinus Torvalds kfree(nctl);
9511da177e4SLinus Torvalds kfree(gctl);
9521da177e4SLinus Torvalds kfree(val);
9531da177e4SLinus Torvalds return err;
9541da177e4SLinus Torvalds }
9551da177e4SLinus Torvalds
snd_emu10k1_del_controls(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)956eb4698f3STakashi Iwai static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
957d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
958d42fe63dSTakashi Iwai bool in_kernel)
9591da177e4SLinus Torvalds {
9601da177e4SLinus Torvalds unsigned int i;
9612e468867STakashi Iwai struct emu10k1_ctl_elem_id id;
962eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl;
963eb4698f3STakashi Iwai struct snd_card *card = emu->card;
96481b45090STakashi Iwai int err;
9651da177e4SLinus Torvalds
96681b45090STakashi Iwai for (i = 0; i < icode->gpr_del_control_count; i++) {
96781b45090STakashi Iwai err = copy_ctl_elem_id(icode->gpr_del_controls, i, &id,
96881b45090STakashi Iwai in_kernel);
96981b45090STakashi Iwai if (err < 0)
97081b45090STakashi Iwai return err;
9711da177e4SLinus Torvalds ctl = snd_emu10k1_look_for_ctl(emu, &id);
9721da177e4SLinus Torvalds if (ctl)
9731da177e4SLinus Torvalds snd_ctl_remove(card, ctl->kcontrol);
9741da177e4SLinus Torvalds }
9751da177e4SLinus Torvalds return 0;
9761da177e4SLinus Torvalds }
9771da177e4SLinus Torvalds
snd_emu10k1_list_controls(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode)978eb4698f3STakashi Iwai static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
979eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode)
9801da177e4SLinus Torvalds {
9811da177e4SLinus Torvalds unsigned int i = 0, j;
9821da177e4SLinus Torvalds unsigned int total = 0;
983eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *gctl;
984eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_ctl *ctl;
985eb4698f3STakashi Iwai struct snd_ctl_elem_id *id;
9861da177e4SLinus Torvalds
9871da177e4SLinus Torvalds gctl = kmalloc(sizeof(*gctl), GFP_KERNEL);
9881da177e4SLinus Torvalds if (! gctl)
9891da177e4SLinus Torvalds return -ENOMEM;
9901da177e4SLinus Torvalds
991c2d7051eSMatthias Kaehlcke list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) {
9921da177e4SLinus Torvalds total++;
993f7ba7fc6STakashi Iwai if (icode->gpr_list_controls &&
994f7ba7fc6STakashi Iwai i < icode->gpr_list_control_count) {
9951da177e4SLinus Torvalds memset(gctl, 0, sizeof(*gctl));
9961da177e4SLinus Torvalds id = &ctl->kcontrol->id;
99781b45090STakashi Iwai gctl->id.iface = (__force int)id->iface;
99875b1a8f9SJoe Perches strscpy(gctl->id.name, id->name, sizeof(gctl->id.name));
9991da177e4SLinus Torvalds gctl->id.index = id->index;
10001da177e4SLinus Torvalds gctl->id.device = id->device;
10011da177e4SLinus Torvalds gctl->id.subdevice = id->subdevice;
10021da177e4SLinus Torvalds gctl->vcount = ctl->vcount;
10031da177e4SLinus Torvalds gctl->count = ctl->count;
10041da177e4SLinus Torvalds for (j = 0; j < 32; j++) {
10051da177e4SLinus Torvalds gctl->gpr[j] = ctl->gpr[j];
10061da177e4SLinus Torvalds gctl->value[j] = ctl->value[j];
10071da177e4SLinus Torvalds }
10081da177e4SLinus Torvalds gctl->min = ctl->min;
10091da177e4SLinus Torvalds gctl->max = ctl->max;
10101da177e4SLinus Torvalds gctl->translation = ctl->translation;
1011f7ba7fc6STakashi Iwai if (copy_gctl_to_user(emu, icode->gpr_list_controls,
1012f7ba7fc6STakashi Iwai gctl, i)) {
10131da177e4SLinus Torvalds kfree(gctl);
10141da177e4SLinus Torvalds return -EFAULT;
10151da177e4SLinus Torvalds }
10161da177e4SLinus Torvalds i++;
10171da177e4SLinus Torvalds }
10181da177e4SLinus Torvalds }
10191da177e4SLinus Torvalds icode->gpr_list_control_total = total;
10201da177e4SLinus Torvalds kfree(gctl);
10211da177e4SLinus Torvalds return 0;
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds
snd_emu10k1_icode_poke(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode,bool in_kernel)1024eb4698f3STakashi Iwai static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
1025d42fe63dSTakashi Iwai struct snd_emu10k1_fx8010_code *icode,
1026d42fe63dSTakashi Iwai bool in_kernel)
10271da177e4SLinus Torvalds {
10281da177e4SLinus Torvalds int err = 0;
10291da177e4SLinus Torvalds
103062932df8SIngo Molnar mutex_lock(&emu->fx8010.lock);
1031d42fe63dSTakashi Iwai err = snd_emu10k1_verify_controls(emu, icode, in_kernel);
1032d42fe63dSTakashi Iwai if (err < 0)
10331da177e4SLinus Torvalds goto __error;
103475b1a8f9SJoe Perches strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
10351da177e4SLinus Torvalds /* stop FX processor - this may be dangerous, but it's better to miss
10361da177e4SLinus Torvalds some samples than generate wrong ones - [jk] */
10371da177e4SLinus Torvalds if (emu->audigy)
10381da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
10391da177e4SLinus Torvalds else
10401da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
10411da177e4SLinus Torvalds /* ok, do the main job */
1042d42fe63dSTakashi Iwai err = snd_emu10k1_del_controls(emu, icode, in_kernel);
1043d42fe63dSTakashi Iwai if (err < 0)
1044d42fe63dSTakashi Iwai goto __error;
1045d42fe63dSTakashi Iwai err = snd_emu10k1_gpr_poke(emu, icode, in_kernel);
1046d42fe63dSTakashi Iwai if (err < 0)
1047d42fe63dSTakashi Iwai goto __error;
1048d42fe63dSTakashi Iwai err = snd_emu10k1_tram_poke(emu, icode, in_kernel);
1049d42fe63dSTakashi Iwai if (err < 0)
1050d42fe63dSTakashi Iwai goto __error;
1051d42fe63dSTakashi Iwai err = snd_emu10k1_code_poke(emu, icode, in_kernel);
1052d42fe63dSTakashi Iwai if (err < 0)
1053d42fe63dSTakashi Iwai goto __error;
1054d42fe63dSTakashi Iwai err = snd_emu10k1_add_controls(emu, icode, in_kernel);
1055d42fe63dSTakashi Iwai if (err < 0)
10561da177e4SLinus Torvalds goto __error;
10571da177e4SLinus Torvalds /* start FX processor when the DSP code is updated */
10581da177e4SLinus Torvalds if (emu->audigy)
10591da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
10601da177e4SLinus Torvalds else
10611da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
10621da177e4SLinus Torvalds __error:
106362932df8SIngo Molnar mutex_unlock(&emu->fx8010.lock);
10641da177e4SLinus Torvalds return err;
10651da177e4SLinus Torvalds }
10661da177e4SLinus Torvalds
snd_emu10k1_icode_peek(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_code * icode)1067eb4698f3STakashi Iwai static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
1068eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode)
10691da177e4SLinus Torvalds {
10701da177e4SLinus Torvalds int err;
10711da177e4SLinus Torvalds
107262932df8SIngo Molnar mutex_lock(&emu->fx8010.lock);
107375b1a8f9SJoe Perches strscpy(icode->name, emu->fx8010.name, sizeof(icode->name));
10741da177e4SLinus Torvalds /* ok, do the main job */
10751da177e4SLinus Torvalds err = snd_emu10k1_gpr_peek(emu, icode);
10761da177e4SLinus Torvalds if (err >= 0)
10771da177e4SLinus Torvalds err = snd_emu10k1_tram_peek(emu, icode);
10781da177e4SLinus Torvalds if (err >= 0)
10791da177e4SLinus Torvalds err = snd_emu10k1_code_peek(emu, icode);
10801da177e4SLinus Torvalds if (err >= 0)
10811da177e4SLinus Torvalds err = snd_emu10k1_list_controls(emu, icode);
108262932df8SIngo Molnar mutex_unlock(&emu->fx8010.lock);
10831da177e4SLinus Torvalds return err;
10841da177e4SLinus Torvalds }
10851da177e4SLinus Torvalds
snd_emu10k1_ipcm_poke(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_pcm_rec * ipcm)1086eb4698f3STakashi Iwai static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
1087eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm_rec *ipcm)
10881da177e4SLinus Torvalds {
10891da177e4SLinus Torvalds unsigned int i;
10901da177e4SLinus Torvalds int err = 0;
1091eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm;
10921da177e4SLinus Torvalds
10931da177e4SLinus Torvalds if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
10941da177e4SLinus Torvalds return -EINVAL;
10955ae4f61fSGustavo A. R. Silva ipcm->substream = array_index_nospec(ipcm->substream,
10965ae4f61fSGustavo A. R. Silva EMU10K1_FX8010_PCM_COUNT);
10971da177e4SLinus Torvalds if (ipcm->channels > 32)
10981da177e4SLinus Torvalds return -EINVAL;
10991da177e4SLinus Torvalds pcm = &emu->fx8010.pcm[ipcm->substream];
110062932df8SIngo Molnar mutex_lock(&emu->fx8010.lock);
11011da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock);
11021da177e4SLinus Torvalds if (pcm->opened) {
11031da177e4SLinus Torvalds err = -EBUSY;
11041da177e4SLinus Torvalds goto __error;
11051da177e4SLinus Torvalds }
11061da177e4SLinus Torvalds if (ipcm->channels == 0) { /* remove */
11071da177e4SLinus Torvalds pcm->valid = 0;
11081da177e4SLinus Torvalds } else {
11091da177e4SLinus Torvalds /* FIXME: we need to add universal code to the PCM transfer routine */
11101da177e4SLinus Torvalds if (ipcm->channels != 2) {
11111da177e4SLinus Torvalds err = -EINVAL;
11121da177e4SLinus Torvalds goto __error;
11131da177e4SLinus Torvalds }
11141da177e4SLinus Torvalds pcm->valid = 1;
11151da177e4SLinus Torvalds pcm->opened = 0;
11161da177e4SLinus Torvalds pcm->channels = ipcm->channels;
11171da177e4SLinus Torvalds pcm->tram_start = ipcm->tram_start;
11181da177e4SLinus Torvalds pcm->buffer_size = ipcm->buffer_size;
11191da177e4SLinus Torvalds pcm->gpr_size = ipcm->gpr_size;
11201da177e4SLinus Torvalds pcm->gpr_count = ipcm->gpr_count;
11211da177e4SLinus Torvalds pcm->gpr_tmpcount = ipcm->gpr_tmpcount;
11221da177e4SLinus Torvalds pcm->gpr_ptr = ipcm->gpr_ptr;
11231da177e4SLinus Torvalds pcm->gpr_trigger = ipcm->gpr_trigger;
11241da177e4SLinus Torvalds pcm->gpr_running = ipcm->gpr_running;
11251da177e4SLinus Torvalds for (i = 0; i < pcm->channels; i++)
11261da177e4SLinus Torvalds pcm->etram[i] = ipcm->etram[i];
11271da177e4SLinus Torvalds }
11281da177e4SLinus Torvalds __error:
11291da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock);
113062932df8SIngo Molnar mutex_unlock(&emu->fx8010.lock);
11311da177e4SLinus Torvalds return err;
11321da177e4SLinus Torvalds }
11331da177e4SLinus Torvalds
snd_emu10k1_ipcm_peek(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_pcm_rec * ipcm)1134eb4698f3STakashi Iwai static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
1135eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm_rec *ipcm)
11361da177e4SLinus Torvalds {
11371da177e4SLinus Torvalds unsigned int i;
11381da177e4SLinus Torvalds int err = 0;
1139eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm *pcm;
11401da177e4SLinus Torvalds
11411da177e4SLinus Torvalds if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
11421da177e4SLinus Torvalds return -EINVAL;
11435ae4f61fSGustavo A. R. Silva ipcm->substream = array_index_nospec(ipcm->substream,
11445ae4f61fSGustavo A. R. Silva EMU10K1_FX8010_PCM_COUNT);
11451da177e4SLinus Torvalds pcm = &emu->fx8010.pcm[ipcm->substream];
114662932df8SIngo Molnar mutex_lock(&emu->fx8010.lock);
11471da177e4SLinus Torvalds spin_lock_irq(&emu->reg_lock);
11481da177e4SLinus Torvalds ipcm->channels = pcm->channels;
11491da177e4SLinus Torvalds ipcm->tram_start = pcm->tram_start;
11501da177e4SLinus Torvalds ipcm->buffer_size = pcm->buffer_size;
11511da177e4SLinus Torvalds ipcm->gpr_size = pcm->gpr_size;
11521da177e4SLinus Torvalds ipcm->gpr_ptr = pcm->gpr_ptr;
11531da177e4SLinus Torvalds ipcm->gpr_count = pcm->gpr_count;
11541da177e4SLinus Torvalds ipcm->gpr_tmpcount = pcm->gpr_tmpcount;
11551da177e4SLinus Torvalds ipcm->gpr_trigger = pcm->gpr_trigger;
11561da177e4SLinus Torvalds ipcm->gpr_running = pcm->gpr_running;
11571da177e4SLinus Torvalds for (i = 0; i < pcm->channels; i++)
11581da177e4SLinus Torvalds ipcm->etram[i] = pcm->etram[i];
11591da177e4SLinus Torvalds ipcm->res1 = ipcm->res2 = 0;
11601da177e4SLinus Torvalds ipcm->pad = 0;
11611da177e4SLinus Torvalds spin_unlock_irq(&emu->reg_lock);
116262932df8SIngo Molnar mutex_unlock(&emu->fx8010.lock);
11631da177e4SLinus Torvalds return err;
11641da177e4SLinus Torvalds }
11651da177e4SLinus Torvalds
1166edf8e456SMikael Magnusson #define SND_EMU10K1_GPR_CONTROLS 44
1167edf8e456SMikael Magnusson #define SND_EMU10K1_INPUTS 12
11681da177e4SLinus Torvalds #define SND_EMU10K1_PLAYBACK_CHANNELS 8
11691da177e4SLinus Torvalds #define SND_EMU10K1_CAPTURE_CHANNELS 4
11701da177e4SLinus Torvalds
11719fe0731bSOswald Buddenhagen #define HR_VAL(v) ((v) * 0x80000000LL / 100 - 1)
11729fe0731bSOswald Buddenhagen
1173e23e7a14SBill Pemberton static void
snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr * ctl,const char * name,int gpr,int defval,int defval_hr)11749fe0731bSOswald Buddenhagen snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
11759fe0731bSOswald Buddenhagen const char *name, int gpr, int defval, int defval_hr)
11761da177e4SLinus Torvalds {
117781b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
11781da177e4SLinus Torvalds strcpy(ctl->id.name, name);
11791da177e4SLinus Torvalds ctl->vcount = ctl->count = 1;
11804daf7a0cSClemens Ladisch if (high_res_gpr_volume) {
11811298bc97SOswald Buddenhagen ctl->min = -1;
11824daf7a0cSClemens Ladisch ctl->max = 0x7fffffff;
11834daf7a0cSClemens Ladisch ctl->tlv = snd_emu10k1_db_linear;
11841298bc97SOswald Buddenhagen ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
11859fe0731bSOswald Buddenhagen defval = defval_hr;
11864daf7a0cSClemens Ladisch } else {
11871da177e4SLinus Torvalds ctl->min = 0;
11881da177e4SLinus Torvalds ctl->max = 100;
1189f7ba7fc6STakashi Iwai ctl->tlv = snd_emu10k1_db_scale1;
11901298bc97SOswald Buddenhagen ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
11911da177e4SLinus Torvalds }
1192bb5ceb43SOswald Buddenhagen ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
11934daf7a0cSClemens Ladisch }
11949fe0731bSOswald Buddenhagen #define snd_emu10k1_init_mono_control(ctl, name, gpr, defval) \
11959fe0731bSOswald Buddenhagen snd_emu10k1_init_mono_control2(ctl, name, gpr, defval, HR_VAL(defval))
11961da177e4SLinus Torvalds
1197e23e7a14SBill Pemberton static void
snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr * ctl,const char * name,int gpr,int defval,int defval_hr)11989fe0731bSOswald Buddenhagen snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
11999fe0731bSOswald Buddenhagen const char *name, int gpr, int defval, int defval_hr)
12001da177e4SLinus Torvalds {
120181b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
12021da177e4SLinus Torvalds strcpy(ctl->id.name, name);
12031da177e4SLinus Torvalds ctl->vcount = ctl->count = 2;
12044daf7a0cSClemens Ladisch if (high_res_gpr_volume) {
12051298bc97SOswald Buddenhagen ctl->min = -1;
12064daf7a0cSClemens Ladisch ctl->max = 0x7fffffff;
12074daf7a0cSClemens Ladisch ctl->tlv = snd_emu10k1_db_linear;
12081298bc97SOswald Buddenhagen ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE;
12099fe0731bSOswald Buddenhagen defval = defval_hr;
12104daf7a0cSClemens Ladisch } else {
12111da177e4SLinus Torvalds ctl->min = 0;
12121da177e4SLinus Torvalds ctl->max = 100;
1213f7ba7fc6STakashi Iwai ctl->tlv = snd_emu10k1_db_scale1;
12141298bc97SOswald Buddenhagen ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100;
12151da177e4SLinus Torvalds }
1216bb5ceb43SOswald Buddenhagen ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1217bb5ceb43SOswald Buddenhagen ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
12184daf7a0cSClemens Ladisch }
12199fe0731bSOswald Buddenhagen #define snd_emu10k1_init_stereo_control(ctl, name, gpr, defval) \
12209fe0731bSOswald Buddenhagen snd_emu10k1_init_stereo_control2(ctl, name, gpr, defval, HR_VAL(defval))
12211da177e4SLinus Torvalds
1222e23e7a14SBill Pemberton static void
snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr * ctl,const char * name,int gpr,int defval)1223eb4698f3STakashi Iwai snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1224eb4698f3STakashi Iwai const char *name, int gpr, int defval)
12251da177e4SLinus Torvalds {
122681b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
12271da177e4SLinus Torvalds strcpy(ctl->id.name, name);
12281da177e4SLinus Torvalds ctl->vcount = ctl->count = 1;
12291da177e4SLinus Torvalds ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
12301da177e4SLinus Torvalds ctl->min = 0;
12311da177e4SLinus Torvalds ctl->max = 1;
12321da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
12331da177e4SLinus Torvalds }
12341da177e4SLinus Torvalds
1235e23e7a14SBill Pemberton static void
snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr * ctl,const char * name,int gpr,int defval)1236eb4698f3STakashi Iwai snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1237eb4698f3STakashi Iwai const char *name, int gpr, int defval)
12381da177e4SLinus Torvalds {
123981b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
12401da177e4SLinus Torvalds strcpy(ctl->id.name, name);
12411da177e4SLinus Torvalds ctl->vcount = ctl->count = 2;
12421da177e4SLinus Torvalds ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
12431da177e4SLinus Torvalds ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
12441da177e4SLinus Torvalds ctl->min = 0;
12451da177e4SLinus Torvalds ctl->max = 1;
12461da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
12471da177e4SLinus Torvalds }
12481da177e4SLinus Torvalds
124913d45709SPavel Hofman /*
1250a869057cSOswald Buddenhagen * Used for emu1010 - conversion from 32-bit capture inputs from the FPGA
1251a869057cSOswald Buddenhagen * to 2 x 16-bit registers in Audigy - their values are read via DMA.
125213d45709SPavel Hofman * Conversion is performed by Audigy DSP instructions of FX8010.
125313d45709SPavel Hofman */
snd_emu10k1_audigy_dsp_convert_32_to_2x16(struct snd_emu10k1_fx8010_code * icode,u32 * ptr,int tmp,int bit_shifter16,int reg_in,int reg_out)12544c7bfbcfSOswald Buddenhagen static void snd_emu10k1_audigy_dsp_convert_32_to_2x16(
12559f4bd5ddSJames Courtier-Dutton struct snd_emu10k1_fx8010_code *icode,
12569f4bd5ddSJames Courtier-Dutton u32 *ptr, int tmp, int bit_shifter16,
12579f4bd5ddSJames Courtier-Dutton int reg_in, int reg_out)
12589f4bd5ddSJames Courtier-Dutton {
12594c7bfbcfSOswald Buddenhagen // This leaves the low word in place, which is fine,
12604c7bfbcfSOswald Buddenhagen // as the low bits are completely ignored subsequently.
12614c7bfbcfSOswald Buddenhagen // reg_out[1] = reg_in
12624c7bfbcfSOswald Buddenhagen A_OP(icode, ptr, iACC3, reg_out + 1, reg_in, A_C_00000000, A_C_00000000);
12634c7bfbcfSOswald Buddenhagen // It is fine to read reg_in multiple times.
12644c7bfbcfSOswald Buddenhagen // tmp = reg_in << 15
12654c7bfbcfSOswald Buddenhagen A_OP(icode, ptr, iMACINT1, A_GPR(tmp), A_C_00000000, reg_in, A_GPR(bit_shifter16));
12664c7bfbcfSOswald Buddenhagen // Left-shift once more. This is a separate step, as the
12674c7bfbcfSOswald Buddenhagen // signed multiplication would clobber the MSB.
12684c7bfbcfSOswald Buddenhagen // reg_out[0] = tmp + ((tmp << 31) >> 31)
12694c7bfbcfSOswald Buddenhagen A_OP(icode, ptr, iMAC3, reg_out, A_GPR(tmp), A_GPR(tmp), A_C_80000000);
12709f4bd5ddSJames Courtier-Dutton }
12711da177e4SLinus Torvalds
1272a746516dSOswald Buddenhagen #define ENUM_GPR(name, size) name, name ## _dummy = name + (size) - 1
1273a746516dSOswald Buddenhagen
12741da177e4SLinus Torvalds /*
12751da177e4SLinus Torvalds * initial DSP configuration for Audigy
12761da177e4SLinus Torvalds */
12771da177e4SLinus Torvalds
_snd_emu10k1_audigy_init_efx(struct snd_emu10k1 * emu)1278e23e7a14SBill Pemberton static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
12791da177e4SLinus Torvalds {
1280a746516dSOswald Buddenhagen int err, z, nctl;
1281a746516dSOswald Buddenhagen enum {
1282a746516dSOswald Buddenhagen ENUM_GPR(playback, SND_EMU10K1_PLAYBACK_CHANNELS),
1283a746516dSOswald Buddenhagen ENUM_GPR(stereo_mix, 2),
1284a746516dSOswald Buddenhagen ENUM_GPR(capture, 2),
1285a746516dSOswald Buddenhagen ENUM_GPR(bit_shifter16, 1),
1286a746516dSOswald Buddenhagen // The fixed allocation of these breaks the pattern, but why not.
1287a746516dSOswald Buddenhagen // Splitting these into left/right is questionable, as it will break
1288a746516dSOswald Buddenhagen // down for center/lfe. But it works for stereo/quadro, so whatever.
1289a746516dSOswald Buddenhagen ENUM_GPR(bass_gpr, 2 * 5), // two sides, five coefficients
1290a746516dSOswald Buddenhagen ENUM_GPR(treble_gpr, 2 * 5),
1291a746516dSOswald Buddenhagen ENUM_GPR(bass_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4), // four delay stages
1292a746516dSOswald Buddenhagen ENUM_GPR(treble_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4),
1293a746516dSOswald Buddenhagen ENUM_GPR(tmp, 3),
1294a746516dSOswald Buddenhagen num_static_gprs
1295a746516dSOswald Buddenhagen };
1296a746516dSOswald Buddenhagen int gpr = num_static_gprs;
129759f038a0SOswald Buddenhagen u32 ptr, ptr_skip;
1298eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode = NULL;
1299eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
13001da177e4SLinus Torvalds u32 *gpr_map;
13011da177e4SLinus Torvalds
13021da177e4SLinus Torvalds err = -ENOMEM;
1303f1b4863aSGeyslan G. Bem icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1304f1b4863aSGeyslan G. Bem if (!icode)
1305f1b4863aSGeyslan G. Bem return err;
1306f1b4863aSGeyslan G. Bem
130781b45090STakashi Iwai icode->gpr_map = kcalloc(512 + 256 + 256 + 2 * 1024,
1308f1b4863aSGeyslan G. Bem sizeof(u_int32_t), GFP_KERNEL);
1309f1b4863aSGeyslan G. Bem if (!icode->gpr_map)
1310f1b4863aSGeyslan G. Bem goto __err_gpr;
1311f1b4863aSGeyslan G. Bem controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1312f1b4863aSGeyslan G. Bem sizeof(*controls), GFP_KERNEL);
1313f1b4863aSGeyslan G. Bem if (!controls)
1314f1b4863aSGeyslan G. Bem goto __err_ctrls;
1315f1b4863aSGeyslan G. Bem
131681b45090STakashi Iwai gpr_map = icode->gpr_map;
13171da177e4SLinus Torvalds
13181da177e4SLinus Torvalds icode->tram_data_map = icode->gpr_map + 512;
13191da177e4SLinus Torvalds icode->tram_addr_map = icode->tram_data_map + 256;
13201da177e4SLinus Torvalds icode->code = icode->tram_addr_map + 256;
13211da177e4SLinus Torvalds
13221da177e4SLinus Torvalds /* clear free GPRs */
1323e922da40SOswald Buddenhagen memset(icode->gpr_valid, 0xff, 512 / 8);
13241da177e4SLinus Torvalds
13251da177e4SLinus Torvalds /* clear TRAM data & address lines */
1326e922da40SOswald Buddenhagen memset(icode->tram_valid, 0xff, 256 / 8);
13271da177e4SLinus Torvalds
13281da177e4SLinus Torvalds strcpy(icode->name, "Audigy DSP code for ALSA");
13291da177e4SLinus Torvalds ptr = 0;
13301da177e4SLinus Torvalds nctl = 0;
1331a746516dSOswald Buddenhagen gpr_map[bit_shifter16] = 0x00008000;
13321da177e4SLinus Torvalds
133319b99fbaSJames Courtier-Dutton #if 1
133413d45709SPavel Hofman /* PCM front Playback Volume (independent from stereo mix)
13351298bc97SOswald Buddenhagen * playback = -gpr * FXBUS_PCM_LEFT_FRONT >> 31
13361298bc97SOswald Buddenhagen * where gpr contains negated attenuation from corresponding mixer control
133713d45709SPavel Hofman * (snd_emu10k1_init_stereo_control)
133813d45709SPavel Hofman */
13391298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
13401298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
13411da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
13421da177e4SLinus Torvalds gpr += 2;
13431da177e4SLinus Torvalds
13441da177e4SLinus Torvalds /* PCM Surround Playback (independent from stereo mix) */
13451298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR));
13461298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR));
13471da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
13481da177e4SLinus Torvalds gpr += 2;
13491da177e4SLinus Torvalds
13501da177e4SLinus Torvalds /* PCM Side Playback (independent from stereo mix) */
13512b637da5SLee Revell if (emu->card_capabilities->spk71) {
13521298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE));
13531298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE));
13541da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100);
13551da177e4SLinus Torvalds gpr += 2;
13561da177e4SLinus Torvalds }
13571da177e4SLinus Torvalds
13581da177e4SLinus Torvalds /* PCM Center Playback (independent from stereo mix) */
13591298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER));
13601da177e4SLinus Torvalds snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100);
13611da177e4SLinus Torvalds gpr++;
13621da177e4SLinus Torvalds
13631da177e4SLinus Torvalds /* PCM LFE Playback (independent from stereo mix) */
13641298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE));
13651da177e4SLinus Torvalds snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100);
13661da177e4SLinus Torvalds gpr++;
13671da177e4SLinus Torvalds
13681da177e4SLinus Torvalds /*
13691da177e4SLinus Torvalds * Stereo Mix
13701da177e4SLinus Torvalds */
13711da177e4SLinus Torvalds /* Wave (PCM) Playback Volume (will be renamed later) */
13721298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
13731298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
13741da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100);
13751da177e4SLinus Torvalds gpr += 2;
13761da177e4SLinus Torvalds
13771da177e4SLinus Torvalds /* Synth Playback */
13781298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
13791298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
13801da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100);
13811da177e4SLinus Torvalds gpr += 2;
13821da177e4SLinus Torvalds
13831da177e4SLinus Torvalds /* Wave (PCM) Capture */
13841298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT));
13851298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT));
13861da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0);
13871da177e4SLinus Torvalds gpr += 2;
13881da177e4SLinus Torvalds
13891da177e4SLinus Torvalds /* Synth Capture */
13901298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT));
13911298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT));
13921da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0);
13931da177e4SLinus Torvalds gpr += 2;
13941da177e4SLinus Torvalds
1395bcdbd3b7SOswald Buddenhagen // We need to double the volume, as we configure the voices for half volume,
1396bcdbd3b7SOswald Buddenhagen // which is necessary for bit-identical reproduction.
1397bcdbd3b7SOswald Buddenhagen { static_assert(stereo_mix == playback + SND_EMU10K1_PLAYBACK_CHANNELS); }
1398bcdbd3b7SOswald Buddenhagen for (z = 0; z < SND_EMU10K1_PLAYBACK_CHANNELS + 2; z++)
1399bcdbd3b7SOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_GPR(playback + z), A_GPR(playback + z), A_GPR(playback + z), A_C_00000000);
1400bcdbd3b7SOswald Buddenhagen
14011da177e4SLinus Torvalds /*
14021da177e4SLinus Torvalds * inputs
14031da177e4SLinus Torvalds */
14041da177e4SLinus Torvalds #define A_ADD_VOLUME_IN(var,vol,input) \
14051298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
14061da177e4SLinus Torvalds
1407190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) {
1408a869057cSOswald Buddenhagen /* EMU1010 DSP 0 and DSP 1 Capture */
1409a869057cSOswald Buddenhagen // The 24 MSB hold the actual value. We implicitly discard the 16 LSB.
141090fd5ce5SJames Courtier-Dutton if (emu->card_capabilities->ca0108_chip) {
14114102ac29SOswald Buddenhagen // For unclear reasons, the EMU32IN cannot be the Y operand!
14121298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A3_EMU32IN(0x0), A_GPR(gpr));
1413f549466bSOswald Buddenhagen // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
1414f549466bSOswald Buddenhagen // need to be delayed as well; we use an auxiliary register for that.
14151298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
1416f549466bSOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000);
141790fd5ce5SJames Courtier-Dutton } else {
14181298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_P16VIN(0x0), A_GPR(gpr));
1419f549466bSOswald Buddenhagen // A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
1420f549466bSOswald Buddenhagen // need to be delayed as well; we use an auxiliary register for that.
14211298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1));
1422f549466bSOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
142390fd5ce5SJames Courtier-Dutton }
14249f4bd5ddSJames Courtier-Dutton snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0);
1425f549466bSOswald Buddenhagen gpr_map[gpr + 2] = 0x00000000;
1426f549466bSOswald Buddenhagen gpr += 3;
14276175ccd1SOswald Buddenhagen } else {
1428de0dc310SOswald Buddenhagen if (emu->card_capabilities->ac97_chip) {
14291da177e4SLinus Torvalds /* AC'97 Playback Volume - used only for mic (renamed later) */
14301da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L);
14311da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R);
14321da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0);
14331da177e4SLinus Torvalds gpr += 2;
14341da177e4SLinus Torvalds /* AC'97 Capture Volume - used only for mic */
14351da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L);
14361da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R);
14371da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0);
14381da177e4SLinus Torvalds gpr += 2;
14391da177e4SLinus Torvalds
14401da177e4SLinus Torvalds /* mic capture buffer */
14419d2f3863SOswald Buddenhagen A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), A_C_40000000, A_EXTIN(A_EXTIN_AC97_R));
1442de0dc310SOswald Buddenhagen }
14431da177e4SLinus Torvalds
14441da177e4SLinus Torvalds /* Audigy CD Playback Volume */
14451da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L);
14461da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R);
14471da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
14482b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume",
14491da177e4SLinus Torvalds gpr, 0);
14501da177e4SLinus Torvalds gpr += 2;
14511da177e4SLinus Torvalds /* Audigy CD Capture Volume */
14521da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L);
14531da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R);
14541da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
14552b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume",
14561da177e4SLinus Torvalds gpr, 0);
14571da177e4SLinus Torvalds gpr += 2;
14581da177e4SLinus Torvalds
14591da177e4SLinus Torvalds /* Optical SPDIF Playback Volume */
14601da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
14611da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
146210e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
14631da177e4SLinus Torvalds gpr += 2;
14641da177e4SLinus Torvalds /* Optical SPDIF Capture Volume */
14651da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
14661da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
146710e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
14681da177e4SLinus Torvalds gpr += 2;
14691da177e4SLinus Torvalds
14701da177e4SLinus Torvalds /* Line2 Playback Volume */
14711da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L);
14721da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R);
14731da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
14742b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume",
14751da177e4SLinus Torvalds gpr, 0);
14761da177e4SLinus Torvalds gpr += 2;
14771da177e4SLinus Torvalds /* Line2 Capture Volume */
14781da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L);
14791da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R);
14801da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
14812b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume",
14821da177e4SLinus Torvalds gpr, 0);
14831da177e4SLinus Torvalds gpr += 2;
14841da177e4SLinus Torvalds
14851da177e4SLinus Torvalds /* Philips ADC Playback Volume */
14861da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L);
14871da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R);
14881da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0);
14891da177e4SLinus Torvalds gpr += 2;
14901da177e4SLinus Torvalds /* Philips ADC Capture Volume */
14911da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L);
14921da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R);
14931da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0);
14941da177e4SLinus Torvalds gpr += 2;
14951da177e4SLinus Torvalds
14961da177e4SLinus Torvalds /* Aux2 Playback Volume */
14971da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L);
14981da177e4SLinus Torvalds A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R);
14991da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
15002b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume",
15011da177e4SLinus Torvalds gpr, 0);
15021da177e4SLinus Torvalds gpr += 2;
15031da177e4SLinus Torvalds /* Aux2 Capture Volume */
15041da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L);
15051da177e4SLinus Torvalds A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R);
15061da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++],
15072b637da5SLee Revell emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume",
15081da177e4SLinus Torvalds gpr, 0);
15091da177e4SLinus Torvalds gpr += 2;
15106175ccd1SOswald Buddenhagen }
15111da177e4SLinus Torvalds
15121da177e4SLinus Torvalds /* Stereo Mix Front Playback Volume */
15131298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix));
15141298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1));
15151da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100);
15161da177e4SLinus Torvalds gpr += 2;
15171da177e4SLinus Torvalds
15181da177e4SLinus Torvalds /* Stereo Mix Surround Playback */
15191298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix));
15201298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1));
15211da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0);
15221da177e4SLinus Torvalds gpr += 2;
15231da177e4SLinus Torvalds
15241da177e4SLinus Torvalds /* Stereo Mix Center Playback */
15251da177e4SLinus Torvalds /* Center = sub = Left/2 + Right/2 */
15269d2f3863SOswald Buddenhagen A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1));
15271298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp));
15281da177e4SLinus Torvalds snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0);
15291da177e4SLinus Torvalds gpr++;
15301da177e4SLinus Torvalds
15311da177e4SLinus Torvalds /* Stereo Mix LFE Playback */
15321298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp));
15331da177e4SLinus Torvalds snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0);
15341da177e4SLinus Torvalds gpr++;
15351da177e4SLinus Torvalds
15362b637da5SLee Revell if (emu->card_capabilities->spk71) {
15371da177e4SLinus Torvalds /* Stereo Mix Side Playback */
15381298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix));
15391298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1));
15401da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0);
15411da177e4SLinus Torvalds gpr += 2;
15421da177e4SLinus Torvalds }
15431da177e4SLinus Torvalds
15441da177e4SLinus Torvalds /*
15451da177e4SLinus Torvalds * outputs
15461da177e4SLinus Torvalds */
15471da177e4SLinus Torvalds #define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src))
15481da177e4SLinus Torvalds #define A_PUT_STEREO_OUTPUT(out1,out2,src) \
15491da177e4SLinus Torvalds {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);}
15501da177e4SLinus Torvalds
15511da177e4SLinus Torvalds #define _A_SWITCH(icode, ptr, dst, src, sw) \
15521da177e4SLinus Torvalds A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw);
15531da177e4SLinus Torvalds #define A_SWITCH(icode, ptr, dst, src, sw) \
15541da177e4SLinus Torvalds _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw))
15551da177e4SLinus Torvalds #define _A_SWITCH_NEG(icode, ptr, dst, src) \
15561da177e4SLinus Torvalds A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001);
15571da177e4SLinus Torvalds #define A_SWITCH_NEG(icode, ptr, dst, src) \
15581da177e4SLinus Torvalds _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src))
15591da177e4SLinus Torvalds
15601da177e4SLinus Torvalds
15611da177e4SLinus Torvalds /*
15621da177e4SLinus Torvalds * Process tone control
15631da177e4SLinus Torvalds */
15641da177e4SLinus Torvalds ctl = &controls[nctl + 0];
156581b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
15661da177e4SLinus Torvalds strcpy(ctl->id.name, "Tone Control - Bass");
15671da177e4SLinus Torvalds ctl->vcount = 2;
15681da177e4SLinus Torvalds ctl->count = 10;
15691da177e4SLinus Torvalds ctl->min = 0;
15701da177e4SLinus Torvalds ctl->max = 40;
15711da177e4SLinus Torvalds ctl->value[0] = ctl->value[1] = 20;
15721da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
15731da177e4SLinus Torvalds ctl = &controls[nctl + 1];
157481b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
15751da177e4SLinus Torvalds strcpy(ctl->id.name, "Tone Control - Treble");
15761da177e4SLinus Torvalds ctl->vcount = 2;
15771da177e4SLinus Torvalds ctl->count = 10;
15781da177e4SLinus Torvalds ctl->min = 0;
15791da177e4SLinus Torvalds ctl->max = 40;
15801da177e4SLinus Torvalds ctl->value[0] = ctl->value[1] = 20;
15811da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
15821da177e4SLinus Torvalds for (z = 0; z < 5; z++) {
15831da177e4SLinus Torvalds int j;
15841da177e4SLinus Torvalds for (j = 0; j < 2; j++) {
1585a746516dSOswald Buddenhagen controls[nctl + 0].gpr[z * 2 + j] = bass_gpr + z * 2 + j;
1586a746516dSOswald Buddenhagen controls[nctl + 1].gpr[z * 2 + j] = treble_gpr + z * 2 + j;
15871da177e4SLinus Torvalds }
15881da177e4SLinus Torvalds }
158959f038a0SOswald Buddenhagen nctl += 2;
159059f038a0SOswald Buddenhagen
159159f038a0SOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_C_00000000, A_GPR(gpr), A_C_00000000, A_C_00000000);
159259f038a0SOswald Buddenhagen snd_emu10k1_init_mono_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0);
159359f038a0SOswald Buddenhagen gpr++;
159459f038a0SOswald Buddenhagen A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_CC_REG_ZERO, A_GPR(gpr));
159559f038a0SOswald Buddenhagen ptr_skip = ptr;
15961da177e4SLinus Torvalds for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */
15971da177e4SLinus Torvalds int j, k, l, d;
15981da177e4SLinus Torvalds for (j = 0; j < 2; j++) { /* left/right */
1599a746516dSOswald Buddenhagen k = bass_tmp + (z * 8) + (j * 4);
1600a746516dSOswald Buddenhagen l = treble_tmp + (z * 8) + (j * 4);
160159f038a0SOswald Buddenhagen d = playback + z * 2 + j;
16021da177e4SLinus Torvalds
1603a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(bass_gpr + 0 + j));
1604a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(bass_gpr + 4 + j));
1605a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(bass_gpr + 2 + j));
1606a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(bass_gpr + 8 + j));
1607a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(bass_gpr + 6 + j));
16081da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000);
16091da177e4SLinus Torvalds
1610a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(treble_gpr + 0 + j));
1611a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(treble_gpr + 4 + j));
1612a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(treble_gpr + 2 + j));
1613a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(treble_gpr + 8 + j));
1614a746516dSOswald Buddenhagen A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(treble_gpr + 6 + j));
16151da177e4SLinus Torvalds A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010);
16161da177e4SLinus Torvalds
16171da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000);
16181da177e4SLinus Torvalds
16191da177e4SLinus Torvalds if (z == 2) /* center */
16201da177e4SLinus Torvalds break;
16211da177e4SLinus Torvalds }
16221da177e4SLinus Torvalds }
162359f038a0SOswald Buddenhagen gpr_map[gpr++] = ptr - ptr_skip;
16241da177e4SLinus Torvalds
16251da177e4SLinus Torvalds /* Master volume (will be renamed later) */
16268cabf83cSOswald Buddenhagen for (z = 0; z < 8; z++)
16271298bc97SOswald Buddenhagen A_OP(icode, &ptr, iMAC1, A_GPR(playback+z), A_C_00000000, A_GPR(gpr), A_GPR(playback+z));
16281da177e4SLinus Torvalds snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0);
1629a746516dSOswald Buddenhagen gpr++;
16301da177e4SLinus Torvalds
1631190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) {
16329f4bd5ddSJames Courtier-Dutton /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */
16336f002b02STakashi Iwai dev_info(emu->card->dev, "EMU outputs on\n");
16349f4bd5ddSJames Courtier-Dutton for (z = 0; z < 8; z++) {
163590fd5ce5SJames Courtier-Dutton if (emu->card_capabilities->ca0108_chip) {
163659f038a0SOswald Buddenhagen A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + z), A_C_00000000, A_C_00000000);
163790fd5ce5SJames Courtier-Dutton } else {
163859f038a0SOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + z), A_C_00000000, A_C_00000000);
16399f4bd5ddSJames Courtier-Dutton }
16409f4bd5ddSJames Courtier-Dutton }
16416175ccd1SOswald Buddenhagen } else {
16426175ccd1SOswald Buddenhagen /* analog speakers */
16436175ccd1SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback);
16446175ccd1SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2);
16456175ccd1SOswald Buddenhagen A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4);
16466175ccd1SOswald Buddenhagen A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5);
16476175ccd1SOswald Buddenhagen if (emu->card_capabilities->spk71)
16486175ccd1SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6);
16496175ccd1SOswald Buddenhagen
16506175ccd1SOswald Buddenhagen /* headphone */
16516175ccd1SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback);
16521da177e4SLinus Torvalds
16531da177e4SLinus Torvalds /* IEC958 Optical Raw Playback Switch */
16541da177e4SLinus Torvalds gpr_map[gpr++] = 0;
16551da177e4SLinus Torvalds gpr_map[gpr++] = 0x1008;
16561da177e4SLinus Torvalds gpr_map[gpr++] = 0xffff0000;
16571da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
16581da177e4SLinus Torvalds A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000);
16591da177e4SLinus Torvalds A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001);
16601da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2));
16611da177e4SLinus Torvalds A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000);
16621da177e4SLinus Torvalds A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z);
16631da177e4SLinus Torvalds A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
166459f038a0SOswald Buddenhagen A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
16651da177e4SLinus Torvalds if ((z==1) && (emu->card_capabilities->spdif_bug)) {
16661da177e4SLinus Torvalds /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */
16676f002b02STakashi Iwai dev_info(emu->card->dev,
16686f002b02STakashi Iwai "Installing spdif_bug patch: %s\n",
16696f002b02STakashi Iwai emu->card_capabilities->name);
16701da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000);
16711da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
16721da177e4SLinus Torvalds } else {
16731da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
16741da177e4SLinus Torvalds }
16751da177e4SLinus Torvalds }
167610e8d78aSClemens Ladisch snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
16771da177e4SLinus Torvalds gpr += 2;
16781da177e4SLinus Torvalds
167959f038a0SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2);
168059f038a0SOswald Buddenhagen A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4);
168159f038a0SOswald Buddenhagen A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5);
16826175ccd1SOswald Buddenhagen }
16831da177e4SLinus Torvalds
16841da177e4SLinus Torvalds /* ADC buffer */
16851da177e4SLinus Torvalds #ifdef EMU10K1_CAPTURE_DIGITAL_OUT
168659f038a0SOswald Buddenhagen A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback);
16871da177e4SLinus Torvalds #else
16881da177e4SLinus Torvalds A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture);
16891da177e4SLinus Torvalds A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1);
16901da177e4SLinus Torvalds #endif
16911da177e4SLinus Torvalds
1692190d2c46SJames Courtier-Dutton if (emu->card_capabilities->emu_model) {
1693a869057cSOswald Buddenhagen /* Capture 16 channels of S32_LE sound. */
169490fd5ce5SJames Courtier-Dutton if (emu->card_capabilities->ca0108_chip) {
16956f002b02STakashi Iwai dev_info(emu->card->dev, "EMU2 inputs on\n");
1696a869057cSOswald Buddenhagen /* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */
1697a869057cSOswald Buddenhagen
1698f549466bSOswald Buddenhagen snd_emu10k1_audigy_dsp_convert_32_to_2x16(
1699f549466bSOswald Buddenhagen icode, &ptr, tmp, bit_shifter16, A3_EMU32IN(0), A_FXBUS2(0));
1700f549466bSOswald Buddenhagen // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels
1701f549466bSOswald Buddenhagen // need to be delayed as well; we use an auxiliary register for that.
1702f549466bSOswald Buddenhagen for (z = 1; z < 0x10; z++) {
170390fd5ce5SJames Courtier-Dutton snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp,
170490fd5ce5SJames Courtier-Dutton bit_shifter16,
1705f549466bSOswald Buddenhagen A_GPR(gpr),
170690fd5ce5SJames Courtier-Dutton A_FXBUS2(z*2) );
1707f549466bSOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_GPR(gpr), A3_EMU32IN(z), A_C_00000000, A_C_00000000);
1708f549466bSOswald Buddenhagen gpr_map[gpr++] = 0x00000000;
170990fd5ce5SJames Courtier-Dutton }
171090fd5ce5SJames Courtier-Dutton } else {
17116f002b02STakashi Iwai dev_info(emu->card->dev, "EMU inputs on\n");
1712a869057cSOswald Buddenhagen /* Note that the Alice2 DSPs have 6 I2S inputs which we don't use. */
17139f4bd5ddSJames Courtier-Dutton
171428a97c19STakashi Iwai /*
17156f002b02STakashi Iwai dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n",
171628a97c19STakashi Iwai gpr, tmp);
171728a97c19STakashi Iwai */
17189f4bd5ddSJames Courtier-Dutton snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
17198cabf83cSOswald Buddenhagen /* A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels
17208cabf83cSOswald Buddenhagen * will need to also be delayed; we use an auxiliary register for that. */
17218cabf83cSOswald Buddenhagen for (z = 1; z < 0x10; z++) {
17228cabf83cSOswald Buddenhagen snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr), A_FXBUS2(z * 2) );
17238cabf83cSOswald Buddenhagen A_OP(icode, &ptr, iACC3, A_GPR(gpr), A_P16VIN(z), A_C_00000000, A_C_00000000);
17249f4bd5ddSJames Courtier-Dutton gpr_map[gpr++] = 0x00000000;
17258cabf83cSOswald Buddenhagen }
172690fd5ce5SJames Courtier-Dutton }
17279f4bd5ddSJames Courtier-Dutton
17289f4bd5ddSJames Courtier-Dutton #if 0
17299f4bd5ddSJames Courtier-Dutton for (z = 4; z < 8; z++) {
17309f4bd5ddSJames Courtier-Dutton A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
17319f4bd5ddSJames Courtier-Dutton }
17329f4bd5ddSJames Courtier-Dutton for (z = 0xc; z < 0x10; z++) {
17339f4bd5ddSJames Courtier-Dutton A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_C_00000000);
17349f4bd5ddSJames Courtier-Dutton }
17359f4bd5ddSJames Courtier-Dutton #endif
17369f4bd5ddSJames Courtier-Dutton } else {
17371da177e4SLinus Torvalds /* EFX capture - capture the 16 EXTINs */
17389f4bd5ddSJames Courtier-Dutton /* Capture 16 channels of S16_LE sound */
17391da177e4SLinus Torvalds for (z = 0; z < 16; z++) {
17401da177e4SLinus Torvalds A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
17411da177e4SLinus Torvalds }
17429f4bd5ddSJames Courtier-Dutton }
17431da177e4SLinus Torvalds
174419b99fbaSJames Courtier-Dutton #endif /* JCD test */
17451da177e4SLinus Torvalds /*
17461da177e4SLinus Torvalds * ok, set up done..
17471da177e4SLinus Torvalds */
17481da177e4SLinus Torvalds
1749a746516dSOswald Buddenhagen if (gpr > 512) {
17501da177e4SLinus Torvalds snd_BUG();
17511da177e4SLinus Torvalds err = -EIO;
17521da177e4SLinus Torvalds goto __err;
17531da177e4SLinus Torvalds }
1754a746516dSOswald Buddenhagen
17551da177e4SLinus Torvalds /* clear remaining instruction memory */
17561da177e4SLinus Torvalds while (ptr < 0x400)
17571da177e4SLinus Torvalds A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0);
17581da177e4SLinus Torvalds
17591da177e4SLinus Torvalds icode->gpr_add_control_count = nctl;
176081b45090STakashi Iwai icode->gpr_add_controls = controls;
1761f7ba7fc6STakashi Iwai emu->support_tlv = 1; /* support TLV */
1762d42fe63dSTakashi Iwai err = snd_emu10k1_icode_poke(emu, icode, true);
1763f7ba7fc6STakashi Iwai emu->support_tlv = 0; /* clear again */
17641da177e4SLinus Torvalds
17651da177e4SLinus Torvalds __err:
17661da177e4SLinus Torvalds kfree(controls);
1767f1b4863aSGeyslan G. Bem __err_ctrls:
176881b45090STakashi Iwai kfree(icode->gpr_map);
1769f1b4863aSGeyslan G. Bem __err_gpr:
17701da177e4SLinus Torvalds kfree(icode);
17711da177e4SLinus Torvalds return err;
17721da177e4SLinus Torvalds }
17731da177e4SLinus Torvalds
17741da177e4SLinus Torvalds
17751da177e4SLinus Torvalds /*
17761da177e4SLinus Torvalds * initial DSP configuration for Emu10k1
17771da177e4SLinus Torvalds */
17781da177e4SLinus Torvalds
17791298bc97SOswald Buddenhagen /* Volumes are in the [-2^31, 0] range, zero being mute. */
_volume(struct snd_emu10k1_fx8010_code * icode,u32 * ptr,u32 dst,u32 src,u32 vol)1780e23e7a14SBill Pemberton static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
17811da177e4SLinus Torvalds {
17821298bc97SOswald Buddenhagen OP(icode, ptr, iMAC1, dst, C_00000000, src, vol);
17831da177e4SLinus Torvalds }
_volume_add(struct snd_emu10k1_fx8010_code * icode,u32 * ptr,u32 dst,u32 src,u32 vol)1784e23e7a14SBill Pemberton static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol)
17851da177e4SLinus Torvalds {
17861298bc97SOswald Buddenhagen OP(icode, ptr, iMAC1, dst, dst, src, vol);
17871da177e4SLinus Torvalds }
17881da177e4SLinus Torvalds
17891da177e4SLinus Torvalds #define VOLUME(icode, ptr, dst, src, vol) \
17901da177e4SLinus Torvalds _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol))
17911da177e4SLinus Torvalds #define VOLUME_IN(icode, ptr, dst, src, vol) \
17921da177e4SLinus Torvalds _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
17931da177e4SLinus Torvalds #define VOLUME_ADD(icode, ptr, dst, src, vol) \
17941da177e4SLinus Torvalds _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol))
17951da177e4SLinus Torvalds #define VOLUME_ADDIN(icode, ptr, dst, src, vol) \
17961da177e4SLinus Torvalds _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol))
17971da177e4SLinus Torvalds #define VOLUME_OUT(icode, ptr, dst, src, vol) \
17981298bc97SOswald Buddenhagen _volume(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol))
17991da177e4SLinus Torvalds #define _SWITCH(icode, ptr, dst, src, sw) \
18001da177e4SLinus Torvalds OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw);
18011da177e4SLinus Torvalds #define SWITCH(icode, ptr, dst, src, sw) \
18021da177e4SLinus Torvalds _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw))
18031da177e4SLinus Torvalds #define SWITCH_IN(icode, ptr, dst, src, sw) \
18041da177e4SLinus Torvalds _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw))
18051da177e4SLinus Torvalds #define _SWITCH_NEG(icode, ptr, dst, src) \
18061da177e4SLinus Torvalds OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001);
18071da177e4SLinus Torvalds #define SWITCH_NEG(icode, ptr, dst, src) \
18081da177e4SLinus Torvalds _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src))
18091da177e4SLinus Torvalds
18101da177e4SLinus Torvalds
_snd_emu10k1_init_efx(struct snd_emu10k1 * emu)1811e23e7a14SBill Pemberton static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
18121da177e4SLinus Torvalds {
18131da177e4SLinus Torvalds int err, i, z, gpr, tmp, playback, capture;
181459f038a0SOswald Buddenhagen u32 ptr, ptr_skip;
1815eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode;
1816eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL;
1817eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl;
18181da177e4SLinus Torvalds u32 *gpr_map;
18191da177e4SLinus Torvalds
18201da177e4SLinus Torvalds err = -ENOMEM;
1821f1b4863aSGeyslan G. Bem icode = kzalloc(sizeof(*icode), GFP_KERNEL);
1822f1b4863aSGeyslan G. Bem if (!icode)
1823f1b4863aSGeyslan G. Bem return err;
1824f1b4863aSGeyslan G. Bem
182581b45090STakashi Iwai icode->gpr_map = kcalloc(256 + 160 + 160 + 2 * 512,
1826f1b4863aSGeyslan G. Bem sizeof(u_int32_t), GFP_KERNEL);
1827f1b4863aSGeyslan G. Bem if (!icode->gpr_map)
1828f1b4863aSGeyslan G. Bem goto __err_gpr;
1829f1b4863aSGeyslan G. Bem
1830f1b4863aSGeyslan G. Bem controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
1831f1b4863aSGeyslan G. Bem sizeof(struct snd_emu10k1_fx8010_control_gpr),
1832f1b4863aSGeyslan G. Bem GFP_KERNEL);
1833f1b4863aSGeyslan G. Bem if (!controls)
1834f1b4863aSGeyslan G. Bem goto __err_ctrls;
1835f1b4863aSGeyslan G. Bem
1836f1b4863aSGeyslan G. Bem ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
1837f1b4863aSGeyslan G. Bem if (!ipcm)
1838f1b4863aSGeyslan G. Bem goto __err_ipcm;
1839f1b4863aSGeyslan G. Bem
184081b45090STakashi Iwai gpr_map = icode->gpr_map;
18411da177e4SLinus Torvalds
18421da177e4SLinus Torvalds icode->tram_data_map = icode->gpr_map + 256;
18431da177e4SLinus Torvalds icode->tram_addr_map = icode->tram_data_map + 160;
18441da177e4SLinus Torvalds icode->code = icode->tram_addr_map + 160;
18451da177e4SLinus Torvalds
18461da177e4SLinus Torvalds /* clear free GPRs */
1847e922da40SOswald Buddenhagen memset(icode->gpr_valid, 0xff, 256 / 8);
18481da177e4SLinus Torvalds
18491da177e4SLinus Torvalds /* clear TRAM data & address lines */
1850e922da40SOswald Buddenhagen memset(icode->tram_valid, 0xff, 160 / 8);
18511da177e4SLinus Torvalds
18521da177e4SLinus Torvalds strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
18531da177e4SLinus Torvalds ptr = 0; i = 0;
1854edf8e456SMikael Magnusson /* we have 12 inputs */
18551da177e4SLinus Torvalds playback = SND_EMU10K1_INPUTS;
18561da177e4SLinus Torvalds /* we have 6 playback channels and tone control doubles */
185759f038a0SOswald Buddenhagen capture = playback + SND_EMU10K1_PLAYBACK_CHANNELS;
18581da177e4SLinus Torvalds gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS;
18591da177e4SLinus Torvalds tmp = 0x88; /* we need 4 temporary GPR */
18601da177e4SLinus Torvalds /* from 0x8c to 0xff is the area for tone control */
18611da177e4SLinus Torvalds
18621da177e4SLinus Torvalds /*
18631da177e4SLinus Torvalds * Process FX Buses
18641da177e4SLinus Torvalds */
1865bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000008);
1866bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000008);
1867bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000008);
1868bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000008);
1869bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000008);
1870bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000008);
1871bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000008);
1872bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000008);
18731da177e4SLinus Torvalds OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */
18741da177e4SLinus Torvalds OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */
1875bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000008);
1876bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000008);
18771da177e4SLinus Torvalds
18781da177e4SLinus Torvalds /* Raw S/PDIF PCM */
18791da177e4SLinus Torvalds ipcm->substream = 0;
18801da177e4SLinus Torvalds ipcm->channels = 2;
18811da177e4SLinus Torvalds ipcm->tram_start = 0;
18821da177e4SLinus Torvalds ipcm->buffer_size = (64 * 1024) / 2;
18831da177e4SLinus Torvalds ipcm->gpr_size = gpr++;
18841da177e4SLinus Torvalds ipcm->gpr_ptr = gpr++;
18851da177e4SLinus Torvalds ipcm->gpr_count = gpr++;
18861da177e4SLinus Torvalds ipcm->gpr_tmpcount = gpr++;
18871da177e4SLinus Torvalds ipcm->gpr_trigger = gpr++;
18881da177e4SLinus Torvalds ipcm->gpr_running = gpr++;
18891da177e4SLinus Torvalds ipcm->etram[0] = 0;
18901da177e4SLinus Torvalds ipcm->etram[1] = 1;
18911da177e4SLinus Torvalds
18921da177e4SLinus Torvalds gpr_map[gpr + 0] = 0xfffff000;
18931da177e4SLinus Torvalds gpr_map[gpr + 1] = 0xffff0000;
18941da177e4SLinus Torvalds gpr_map[gpr + 2] = 0x70000000;
18951da177e4SLinus Torvalds gpr_map[gpr + 3] = 0x00000007;
18961da177e4SLinus Torvalds gpr_map[gpr + 4] = 0x001f << 11;
18971da177e4SLinus Torvalds gpr_map[gpr + 5] = 0x001c << 11;
18981da177e4SLinus Torvalds gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */
18991da177e4SLinus Torvalds gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */
19001da177e4SLinus Torvalds gpr_map[gpr + 8] = 0x2000000 + (2<<11);
19011da177e4SLinus Torvalds gpr_map[gpr + 9] = 0x4000000 + (2<<11);
19021da177e4SLinus Torvalds gpr_map[gpr + 10] = 1<<11;
19031da177e4SLinus Torvalds gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */
19041da177e4SLinus Torvalds gpr_map[gpr + 12] = 0;
19051da177e4SLinus Torvalds
19061da177e4SLinus Torvalds /* if the trigger flag is not set, skip */
19071da177e4SLinus Torvalds /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000);
19081da177e4SLinus Torvalds /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6));
19091da177e4SLinus Torvalds /* if the running flag is set, we're running */
19101da177e4SLinus Torvalds /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000);
19111da177e4SLinus Torvalds /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004);
19121da177e4SLinus Torvalds /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */
19131da177e4SLinus Torvalds /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000);
19141da177e4SLinus Torvalds /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5));
19151da177e4SLinus Torvalds /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7));
19161da177e4SLinus Torvalds /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000);
19171da177e4SLinus Torvalds
19181da177e4SLinus Torvalds /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001);
19191da177e4SLinus Torvalds /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000);
19201da177e4SLinus Torvalds /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11));
19211da177e4SLinus Torvalds /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000);
19221da177e4SLinus Torvalds
19231da177e4SLinus Torvalds /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000);
19241da177e4SLinus Torvalds /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
19251da177e4SLinus Torvalds /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
19261da177e4SLinus Torvalds /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
19271da177e4SLinus Torvalds /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2));
19281da177e4SLinus Torvalds
19291da177e4SLinus Torvalds /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000);
19301da177e4SLinus Torvalds /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000);
19311da177e4SLinus Torvalds /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2));
19321da177e4SLinus Torvalds /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001);
19331da177e4SLinus Torvalds /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2));
19341da177e4SLinus Torvalds
19351da177e4SLinus Torvalds /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000);
19361da177e4SLinus Torvalds /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size));
19371da177e4SLinus Torvalds /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001);
19381da177e4SLinus Torvalds /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000);
19391da177e4SLinus Torvalds /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000);
19401da177e4SLinus Torvalds
19411da177e4SLinus Torvalds /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000);
19421da177e4SLinus Torvalds /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002);
19431da177e4SLinus Torvalds /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000);
19441da177e4SLinus Torvalds /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000);
19451da177e4SLinus Torvalds /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000);
19461da177e4SLinus Torvalds
19471da177e4SLinus Torvalds /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001);
19481da177e4SLinus Torvalds /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002);
19491da177e4SLinus Torvalds
19501da177e4SLinus Torvalds /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff);
19511da177e4SLinus Torvalds /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff);
19521da177e4SLinus Torvalds
19531da177e4SLinus Torvalds /* 24: */
19541da177e4SLinus Torvalds gpr += 13;
19551da177e4SLinus Torvalds
19561da177e4SLinus Torvalds /* Wave Playback Volume */
19571da177e4SLinus Torvalds for (z = 0; z < 2; z++)
19581da177e4SLinus Torvalds VOLUME(icode, &ptr, playback + z, z, gpr + z);
19591da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100);
19601da177e4SLinus Torvalds gpr += 2;
19611da177e4SLinus Torvalds
19621da177e4SLinus Torvalds /* Wave Surround Playback Volume */
19631da177e4SLinus Torvalds for (z = 0; z < 2; z++)
19641da177e4SLinus Torvalds VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z);
19651da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0);
19661da177e4SLinus Torvalds gpr += 2;
19671da177e4SLinus Torvalds
19681da177e4SLinus Torvalds /* Wave Center/LFE Playback Volume */
19691da177e4SLinus Torvalds OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000);
1970bcdbd3b7SOswald Buddenhagen OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000004);
19711da177e4SLinus Torvalds VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr);
19721da177e4SLinus Torvalds snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0);
19731da177e4SLinus Torvalds VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr);
19741da177e4SLinus Torvalds snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0);
19751da177e4SLinus Torvalds
19761da177e4SLinus Torvalds /* Wave Capture Volume + Switch */
19771da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
19781da177e4SLinus Torvalds SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z);
19791da177e4SLinus Torvalds VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z);
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0);
19821da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0);
19831da177e4SLinus Torvalds gpr += 4;
19841da177e4SLinus Torvalds
19851da177e4SLinus Torvalds /* Synth Playback Volume */
19861da177e4SLinus Torvalds for (z = 0; z < 2; z++)
19871da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z);
19881da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100);
19891da177e4SLinus Torvalds gpr += 2;
19901da177e4SLinus Torvalds
19911da177e4SLinus Torvalds /* Synth Capture Volume + Switch */
19921da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
19931da177e4SLinus Torvalds SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z);
19941da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
19951da177e4SLinus Torvalds }
19961da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0);
19971da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0);
19981da177e4SLinus Torvalds gpr += 4;
19991da177e4SLinus Torvalds
20001da177e4SLinus Torvalds /* Surround Digital Playback Volume (renamed later without Digital) */
20011da177e4SLinus Torvalds for (z = 0; z < 2; z++)
20021da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z);
20031da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100);
20041da177e4SLinus Torvalds gpr += 2;
20051da177e4SLinus Torvalds
20061da177e4SLinus Torvalds /* Surround Capture Volume + Switch */
20071da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
20081da177e4SLinus Torvalds SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z);
20091da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
20101da177e4SLinus Torvalds }
20111da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0);
20121da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0);
20131da177e4SLinus Torvalds gpr += 4;
20141da177e4SLinus Torvalds
20151da177e4SLinus Torvalds /* Center Playback Volume (renamed later without Digital) */
20161da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr);
20171da177e4SLinus Torvalds snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100);
20181da177e4SLinus Torvalds
20191da177e4SLinus Torvalds /* LFE Playback Volume + Switch (renamed later without Digital) */
20201da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr);
20211da177e4SLinus Torvalds snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100);
20221da177e4SLinus Torvalds
2023edf8e456SMikael Magnusson /* Front Playback Volume */
2024edf8e456SMikael Magnusson for (z = 0; z < 2; z++)
2025edf8e456SMikael Magnusson VOLUME_ADD(icode, &ptr, playback + z, 10 + z, gpr + z);
2026edf8e456SMikael Magnusson snd_emu10k1_init_stereo_control(controls + i++, "Front Playback Volume", gpr, 100);
2027edf8e456SMikael Magnusson gpr += 2;
2028edf8e456SMikael Magnusson
2029edf8e456SMikael Magnusson /* Front Capture Volume + Switch */
2030edf8e456SMikael Magnusson for (z = 0; z < 2; z++) {
2031edf8e456SMikael Magnusson SWITCH(icode, &ptr, tmp + 0, 10 + z, gpr + 2);
2032edf8e456SMikael Magnusson VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
2033edf8e456SMikael Magnusson }
2034edf8e456SMikael Magnusson snd_emu10k1_init_stereo_control(controls + i++, "Front Capture Volume", gpr, 0);
2035edf8e456SMikael Magnusson snd_emu10k1_init_mono_onoff_control(controls + i++, "Front Capture Switch", gpr + 2, 0);
2036edf8e456SMikael Magnusson gpr += 3;
2037edf8e456SMikael Magnusson
20381da177e4SLinus Torvalds /*
20391da177e4SLinus Torvalds * Process inputs
20401da177e4SLinus Torvalds */
20411da177e4SLinus Torvalds
20421da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) {
20431da177e4SLinus Torvalds /* AC'97 Playback Volume */
20441da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++;
20451da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++;
20461da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0);
20471da177e4SLinus Torvalds /* AC'97 Capture Volume */
20481da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++;
20491da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++;
20501da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100);
20511da177e4SLinus Torvalds }
20521da177e4SLinus Torvalds
20531da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) {
20541da177e4SLinus Torvalds /* IEC958 TTL Playback Volume */
20551da177e4SLinus Torvalds for (z = 0; z < 2; z++)
20561da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
205710e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
20581da177e4SLinus Torvalds gpr += 2;
20591da177e4SLinus Torvalds
20601da177e4SLinus Torvalds /* IEC958 TTL Capture Volume + Switch */
20611da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
20621da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
20631da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
20641da177e4SLinus Torvalds }
206510e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
206610e8d78aSClemens Ladisch snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
20671da177e4SLinus Torvalds gpr += 4;
20681da177e4SLinus Torvalds }
20691da177e4SLinus Torvalds
20701da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) {
20711da177e4SLinus Torvalds /* Zoom Video Playback Volume */
20721da177e4SLinus Torvalds for (z = 0; z < 2; z++)
20731da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z);
20741da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0);
20751da177e4SLinus Torvalds gpr += 2;
20761da177e4SLinus Torvalds
20771da177e4SLinus Torvalds /* Zoom Video Capture Volume + Switch */
20781da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
20791da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z);
20801da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
20811da177e4SLinus Torvalds }
20821da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0);
20831da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0);
20841da177e4SLinus Torvalds gpr += 4;
20851da177e4SLinus Torvalds }
20861da177e4SLinus Torvalds
20871da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) {
20881da177e4SLinus Torvalds /* IEC958 Optical Playback Volume */
20891da177e4SLinus Torvalds for (z = 0; z < 2; z++)
20901da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
209110e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
20921da177e4SLinus Torvalds gpr += 2;
20931da177e4SLinus Torvalds
20941da177e4SLinus Torvalds /* IEC958 Optical Capture Volume */
20951da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
20961da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
20971da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
20981da177e4SLinus Torvalds }
209910e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
210010e8d78aSClemens Ladisch snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
21011da177e4SLinus Torvalds gpr += 4;
21021da177e4SLinus Torvalds }
21031da177e4SLinus Torvalds
21041da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) {
21051da177e4SLinus Torvalds /* Line LiveDrive Playback Volume */
21061da177e4SLinus Torvalds for (z = 0; z < 2; z++)
21071da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z);
21081da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0);
21091da177e4SLinus Torvalds gpr += 2;
21101da177e4SLinus Torvalds
21111da177e4SLinus Torvalds /* Line LiveDrive Capture Volume + Switch */
21121da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
21131da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z);
21141da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
21151da177e4SLinus Torvalds }
21161da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0);
21171da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0);
21181da177e4SLinus Torvalds gpr += 4;
21191da177e4SLinus Torvalds }
21201da177e4SLinus Torvalds
21211da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) {
21221da177e4SLinus Torvalds /* IEC958 Coax Playback Volume */
21231da177e4SLinus Torvalds for (z = 0; z < 2; z++)
21241da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
212510e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
21261da177e4SLinus Torvalds gpr += 2;
21271da177e4SLinus Torvalds
21281da177e4SLinus Torvalds /* IEC958 Coax Capture Volume + Switch */
21291da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
21301da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
21311da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
21321da177e4SLinus Torvalds }
213310e8d78aSClemens Ladisch snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
213410e8d78aSClemens Ladisch snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
21351da177e4SLinus Torvalds gpr += 4;
21361da177e4SLinus Torvalds }
21371da177e4SLinus Torvalds
21381da177e4SLinus Torvalds if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) {
21391da177e4SLinus Torvalds /* Line LiveDrive Playback Volume */
21401da177e4SLinus Torvalds for (z = 0; z < 2; z++)
21411da177e4SLinus Torvalds VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z);
21421da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0);
21431da177e4SLinus Torvalds controls[i-1].id.index = 1;
21441da177e4SLinus Torvalds gpr += 2;
21451da177e4SLinus Torvalds
21461da177e4SLinus Torvalds /* Line LiveDrive Capture Volume */
21471da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
21481da177e4SLinus Torvalds SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z);
21491da177e4SLinus Torvalds VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
21501da177e4SLinus Torvalds }
21511da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0);
21521da177e4SLinus Torvalds controls[i-1].id.index = 1;
21531da177e4SLinus Torvalds snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0);
21541da177e4SLinus Torvalds controls[i-1].id.index = 1;
21551da177e4SLinus Torvalds gpr += 4;
21561da177e4SLinus Torvalds }
21571da177e4SLinus Torvalds
21581da177e4SLinus Torvalds /*
21591da177e4SLinus Torvalds * Process tone control
21601da177e4SLinus Torvalds */
21611da177e4SLinus Torvalds ctl = &controls[i + 0];
216281b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
21631da177e4SLinus Torvalds strcpy(ctl->id.name, "Tone Control - Bass");
21641da177e4SLinus Torvalds ctl->vcount = 2;
21651da177e4SLinus Torvalds ctl->count = 10;
21661da177e4SLinus Torvalds ctl->min = 0;
21671da177e4SLinus Torvalds ctl->max = 40;
21681da177e4SLinus Torvalds ctl->value[0] = ctl->value[1] = 20;
2169bfe9fc8aSRaymond Yau ctl->tlv = snd_emu10k1_bass_treble_db_scale;
21701da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
21711da177e4SLinus Torvalds ctl = &controls[i + 1];
217281b45090STakashi Iwai ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
21731da177e4SLinus Torvalds strcpy(ctl->id.name, "Tone Control - Treble");
21741da177e4SLinus Torvalds ctl->vcount = 2;
21751da177e4SLinus Torvalds ctl->count = 10;
21761da177e4SLinus Torvalds ctl->min = 0;
21771da177e4SLinus Torvalds ctl->max = 40;
21781da177e4SLinus Torvalds ctl->value[0] = ctl->value[1] = 20;
2179bfe9fc8aSRaymond Yau ctl->tlv = snd_emu10k1_bass_treble_db_scale;
21801da177e4SLinus Torvalds ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE;
21811da177e4SLinus Torvalds
21821da177e4SLinus Torvalds #define BASS_GPR 0x8c
21831da177e4SLinus Torvalds #define TREBLE_GPR 0x96
21841da177e4SLinus Torvalds
21851da177e4SLinus Torvalds for (z = 0; z < 5; z++) {
21861da177e4SLinus Torvalds int j;
21871da177e4SLinus Torvalds for (j = 0; j < 2; j++) {
21881da177e4SLinus Torvalds controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j;
21891da177e4SLinus Torvalds controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j;
21901da177e4SLinus Torvalds }
21911da177e4SLinus Torvalds }
219259f038a0SOswald Buddenhagen i += 2;
219359f038a0SOswald Buddenhagen
219459f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, C_00000000, GPR(gpr), C_00000000, C_00000000);
219559f038a0SOswald Buddenhagen snd_emu10k1_init_mono_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0);
219659f038a0SOswald Buddenhagen gpr++;
219759f038a0SOswald Buddenhagen OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr));
219859f038a0SOswald Buddenhagen ptr_skip = ptr;
21991da177e4SLinus Torvalds for (z = 0; z < 3; z++) { /* front/rear/center-lfe */
22001da177e4SLinus Torvalds int j, k, l, d;
22011da177e4SLinus Torvalds for (j = 0; j < 2; j++) { /* left/right */
22021da177e4SLinus Torvalds k = 0xa0 + (z * 8) + (j * 4);
22031da177e4SLinus Torvalds l = 0xd0 + (z * 8) + (j * 4);
220459f038a0SOswald Buddenhagen d = playback + z * 2 + j;
22051da177e4SLinus Torvalds
22061da177e4SLinus Torvalds OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j));
22071da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j));
22081da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j));
22091da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j));
22101da177e4SLinus Torvalds OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j));
22111da177e4SLinus Torvalds OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000);
22121da177e4SLinus Torvalds
22131da177e4SLinus Torvalds OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j));
22141da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j));
22151da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j));
22161da177e4SLinus Torvalds OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j));
22171da177e4SLinus Torvalds OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j));
22181da177e4SLinus Torvalds OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010);
22191da177e4SLinus Torvalds
22201da177e4SLinus Torvalds OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000);
22211da177e4SLinus Torvalds
22221da177e4SLinus Torvalds if (z == 2) /* center */
22231da177e4SLinus Torvalds break;
22241da177e4SLinus Torvalds }
22251da177e4SLinus Torvalds }
222659f038a0SOswald Buddenhagen gpr_map[gpr++] = ptr - ptr_skip;
22271da177e4SLinus Torvalds
22281da177e4SLinus Torvalds #undef BASS_GPR
22291da177e4SLinus Torvalds #undef TREBLE_GPR
22301da177e4SLinus Torvalds
22311da177e4SLinus Torvalds /*
22321da177e4SLinus Torvalds * Process outputs
22331da177e4SLinus Torvalds */
22341da177e4SLinus Torvalds if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) {
22351da177e4SLinus Torvalds /* AC'97 Playback Volume */
22361da177e4SLinus Torvalds
22371da177e4SLinus Torvalds for (z = 0; z < 2; z++)
223859f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + z), C_00000000, C_00000000);
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds
22411da177e4SLinus Torvalds if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) {
22421da177e4SLinus Torvalds /* IEC958 Optical Raw Playback Switch */
22431da177e4SLinus Torvalds
22441da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
22451da177e4SLinus Torvalds SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z);
22461da177e4SLinus Torvalds SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z);
224759f038a0SOswald Buddenhagen SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
22481da177e4SLinus Torvalds OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
22491da177e4SLinus Torvalds #ifdef EMU10K1_CAPTURE_DIGITAL_OUT
22501da177e4SLinus Torvalds OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
22511da177e4SLinus Torvalds #endif
22521da177e4SLinus Torvalds }
22531da177e4SLinus Torvalds
225410e8d78aSClemens Ladisch snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
22551da177e4SLinus Torvalds gpr += 2;
22561da177e4SLinus Torvalds }
22571da177e4SLinus Torvalds
22581da177e4SLinus Torvalds if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) {
22591da177e4SLinus Torvalds /* Headphone Playback Volume */
22601da177e4SLinus Torvalds
22611da177e4SLinus Torvalds for (z = 0; z < 2; z++) {
226259f038a0SOswald Buddenhagen SWITCH(icode, &ptr, tmp + 0, playback + 4 + z, gpr + 2 + z);
22631da177e4SLinus Torvalds SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z);
226459f038a0SOswald Buddenhagen SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1);
22651da177e4SLinus Torvalds OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000);
22661da177e4SLinus Torvalds VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z);
22671da177e4SLinus Torvalds }
22681da177e4SLinus Torvalds
22691da177e4SLinus Torvalds snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0);
22701da177e4SLinus Torvalds controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */
22711da177e4SLinus Torvalds snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0);
22721da177e4SLinus Torvalds controls[i-1].id.index = 1;
22731da177e4SLinus Torvalds snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0);
22741da177e4SLinus Torvalds controls[i-1].id.index = 1;
22751da177e4SLinus Torvalds
22761da177e4SLinus Torvalds gpr += 4;
22771da177e4SLinus Torvalds }
22781da177e4SLinus Torvalds
22791da177e4SLinus Torvalds if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R)))
22801da177e4SLinus Torvalds for (z = 0; z < 2; z++)
228159f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000);
22821da177e4SLinus Torvalds
22831da177e4SLinus Torvalds if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R)))
22841da177e4SLinus Torvalds for (z = 0; z < 2; z++)
228559f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000);
22861da177e4SLinus Torvalds
22871da177e4SLinus Torvalds if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) {
22881da177e4SLinus Torvalds #ifndef EMU10K1_CENTER_LFE_FROM_FRONT
228959f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 4), C_00000000, C_00000000);
229059f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 4), C_00000000, C_00000000);
22911da177e4SLinus Torvalds #else
229259f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 0), C_00000000, C_00000000);
229359f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 0), C_00000000, C_00000000);
22941da177e4SLinus Torvalds #endif
22951da177e4SLinus Torvalds }
22961da177e4SLinus Torvalds
22971da177e4SLinus Torvalds if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) {
22981da177e4SLinus Torvalds #ifndef EMU10K1_CENTER_LFE_FROM_FRONT
229959f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 5), C_00000000, C_00000000);
230059f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 5), C_00000000, C_00000000);
23011da177e4SLinus Torvalds #else
230259f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 1), C_00000000, C_00000000);
230359f038a0SOswald Buddenhagen OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 1), C_00000000, C_00000000);
23041da177e4SLinus Torvalds #endif
23051da177e4SLinus Torvalds }
23061da177e4SLinus Torvalds
23071da177e4SLinus Torvalds #ifndef EMU10K1_CAPTURE_DIGITAL_OUT
23081da177e4SLinus Torvalds for (z = 0; z < 2; z++)
23091da177e4SLinus Torvalds OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000);
23101da177e4SLinus Torvalds #endif
23111da177e4SLinus Torvalds
23121da177e4SLinus Torvalds if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP))
23131da177e4SLinus Torvalds OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000);
23141da177e4SLinus Torvalds
23151da177e4SLinus Torvalds /* EFX capture - capture the 16 EXTINS */
23162b637da5SLee Revell if (emu->card_capabilities->sblive51) {
2317db987421SOswald Buddenhagen for (z = 0; z < 16; z++) {
2318db987421SOswald Buddenhagen s8 c = snd_emu10k1_sblive51_fxbus2_map[z];
2319db987421SOswald Buddenhagen if (c != -1)
2320db987421SOswald Buddenhagen OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(c));
2321db987421SOswald Buddenhagen }
23222b637da5SLee Revell } else {
23232b637da5SLee Revell for (z = 0; z < 16; z++)
23241da177e4SLinus Torvalds OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z));
23251da177e4SLinus Torvalds }
23261da177e4SLinus Torvalds
23272b637da5SLee Revell
23281da177e4SLinus Torvalds if (gpr > tmp) {
23291da177e4SLinus Torvalds snd_BUG();
23301da177e4SLinus Torvalds err = -EIO;
23311da177e4SLinus Torvalds goto __err;
23321da177e4SLinus Torvalds }
23331da177e4SLinus Torvalds if (i > SND_EMU10K1_GPR_CONTROLS) {
23341da177e4SLinus Torvalds snd_BUG();
23351da177e4SLinus Torvalds err = -EIO;
23361da177e4SLinus Torvalds goto __err;
23371da177e4SLinus Torvalds }
23381da177e4SLinus Torvalds
23391da177e4SLinus Torvalds /* clear remaining instruction memory */
23401da177e4SLinus Torvalds while (ptr < 0x200)
23411da177e4SLinus Torvalds OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000);
23421da177e4SLinus Torvalds
234312bda107STakashi Iwai err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size);
234412bda107STakashi Iwai if (err < 0)
23451da177e4SLinus Torvalds goto __err;
23461da177e4SLinus Torvalds icode->gpr_add_control_count = i;
234781b45090STakashi Iwai icode->gpr_add_controls = controls;
2348f7ba7fc6STakashi Iwai emu->support_tlv = 1; /* support TLV */
2349d42fe63dSTakashi Iwai err = snd_emu10k1_icode_poke(emu, icode, true);
2350f7ba7fc6STakashi Iwai emu->support_tlv = 0; /* clear again */
23511da177e4SLinus Torvalds if (err >= 0)
23521da177e4SLinus Torvalds err = snd_emu10k1_ipcm_poke(emu, ipcm);
23531da177e4SLinus Torvalds __err:
23541da177e4SLinus Torvalds kfree(ipcm);
2355f1b4863aSGeyslan G. Bem __err_ipcm:
23561da177e4SLinus Torvalds kfree(controls);
2357f1b4863aSGeyslan G. Bem __err_ctrls:
235881b45090STakashi Iwai kfree(icode->gpr_map);
2359f1b4863aSGeyslan G. Bem __err_gpr:
23601da177e4SLinus Torvalds kfree(icode);
23611da177e4SLinus Torvalds return err;
23621da177e4SLinus Torvalds }
23631da177e4SLinus Torvalds
snd_emu10k1_init_efx(struct snd_emu10k1 * emu)2364e23e7a14SBill Pemberton int snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
23651da177e4SLinus Torvalds {
236609668b44STakashi Iwai spin_lock_init(&emu->fx8010.irq_lock);
236709668b44STakashi Iwai INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
23681da177e4SLinus Torvalds if (emu->audigy)
23691da177e4SLinus Torvalds return _snd_emu10k1_audigy_init_efx(emu);
23701da177e4SLinus Torvalds else
23711da177e4SLinus Torvalds return _snd_emu10k1_init_efx(emu);
23721da177e4SLinus Torvalds }
23731da177e4SLinus Torvalds
snd_emu10k1_free_efx(struct snd_emu10k1 * emu)2374eb4698f3STakashi Iwai void snd_emu10k1_free_efx(struct snd_emu10k1 *emu)
23751da177e4SLinus Torvalds {
23761da177e4SLinus Torvalds /* stop processor */
23771da177e4SLinus Torvalds if (emu->audigy)
23781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP);
23791da177e4SLinus Torvalds else
23801da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP);
23811da177e4SLinus Torvalds }
23821da177e4SLinus Torvalds
23839f4bd5ddSJames Courtier-Dutton #if 0 /* FIXME: who use them? */
2384eb4698f3STakashi Iwai int snd_emu10k1_fx8010_tone_control_activate(struct snd_emu10k1 *emu, int output)
23851da177e4SLinus Torvalds {
23867c22f1aaSTakashi Iwai if (output < 0 || output >= 6)
23877c22f1aaSTakashi Iwai return -EINVAL;
23881da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1);
23891da177e4SLinus Torvalds return 0;
23901da177e4SLinus Torvalds }
23911da177e4SLinus Torvalds
2392eb4698f3STakashi Iwai int snd_emu10k1_fx8010_tone_control_deactivate(struct snd_emu10k1 *emu, int output)
23931da177e4SLinus Torvalds {
23947c22f1aaSTakashi Iwai if (output < 0 || output >= 6)
23957c22f1aaSTakashi Iwai return -EINVAL;
23961da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0);
23971da177e4SLinus Torvalds return 0;
23981da177e4SLinus Torvalds }
23991da177e4SLinus Torvalds #endif
24001da177e4SLinus Torvalds
snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 * emu,u32 size)2401eb4698f3STakashi Iwai int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
24021da177e4SLinus Torvalds {
24031da177e4SLinus Torvalds u8 size_reg = 0;
24041da177e4SLinus Torvalds
24051da177e4SLinus Torvalds /* size is in samples */
24061da177e4SLinus Torvalds if (size != 0) {
24071da177e4SLinus Torvalds size = (size - 1) >> 13;
24081da177e4SLinus Torvalds
24091da177e4SLinus Torvalds while (size) {
24101da177e4SLinus Torvalds size >>= 1;
24111da177e4SLinus Torvalds size_reg++;
24121da177e4SLinus Torvalds }
24131da177e4SLinus Torvalds size = 0x2000 << size_reg;
24141da177e4SLinus Torvalds }
24151da177e4SLinus Torvalds if ((emu->fx8010.etram_pages.bytes / 2) == size)
24161da177e4SLinus Torvalds return 0;
24171da177e4SLinus Torvalds spin_lock_irq(&emu->emu_lock);
24181da177e4SLinus Torvalds outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
24191da177e4SLinus Torvalds spin_unlock_irq(&emu->emu_lock);
24201da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TCB, 0, 0);
24219d2f3863SOswald Buddenhagen snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K);
24221da177e4SLinus Torvalds if (emu->fx8010.etram_pages.area != NULL) {
24231da177e4SLinus Torvalds snd_dma_free_pages(&emu->fx8010.etram_pages);
24241da177e4SLinus Torvalds emu->fx8010.etram_pages.area = NULL;
24251da177e4SLinus Torvalds emu->fx8010.etram_pages.bytes = 0;
24261da177e4SLinus Torvalds }
24271da177e4SLinus Torvalds
24281da177e4SLinus Torvalds if (size > 0) {
24296974f8adSTakashi Iwai if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &emu->pci->dev,
24301da177e4SLinus Torvalds size * 2, &emu->fx8010.etram_pages) < 0)
24311da177e4SLinus Torvalds return -ENOMEM;
24321da177e4SLinus Torvalds memset(emu->fx8010.etram_pages.area, 0, size * 2);
24331da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
24341da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
24351da177e4SLinus Torvalds spin_lock_irq(&emu->emu_lock);
24361da177e4SLinus Torvalds outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
24371da177e4SLinus Torvalds spin_unlock_irq(&emu->emu_lock);
24381da177e4SLinus Torvalds }
24391da177e4SLinus Torvalds
24401da177e4SLinus Torvalds return 0;
24411da177e4SLinus Torvalds }
24421da177e4SLinus Torvalds
snd_emu10k1_fx8010_open(struct snd_hwdep * hw,struct file * file)2443eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
24441da177e4SLinus Torvalds {
24451da177e4SLinus Torvalds return 0;
24461da177e4SLinus Torvalds }
24471da177e4SLinus Torvalds
copy_string(char * dst,const char * src,const char * null,int idx)24486fddce26STakashi Iwai static void copy_string(char *dst, const char *src, const char *null, int idx)
24491da177e4SLinus Torvalds {
24501da177e4SLinus Torvalds if (src == NULL)
24511da177e4SLinus Torvalds sprintf(dst, "%s %02X", null, idx);
24521da177e4SLinus Torvalds else
24531da177e4SLinus Torvalds strcpy(dst, src);
24541da177e4SLinus Torvalds }
24551da177e4SLinus Torvalds
snd_emu10k1_fx8010_info(struct snd_emu10k1 * emu,struct snd_emu10k1_fx8010_info * info)245651882453SMariusz Kozlowski static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
2457eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_info *info)
24581da177e4SLinus Torvalds {
24596fddce26STakashi Iwai const char * const *fxbus, * const *extin, * const *extout;
2460e81995a8SOswald Buddenhagen unsigned short extin_mask, extout_mask;
24611da177e4SLinus Torvalds int res;
24621da177e4SLinus Torvalds
24631da177e4SLinus Torvalds info->internal_tram_size = emu->fx8010.itram_size;
24641da177e4SLinus Torvalds info->external_tram_size = emu->fx8010.etram_pages.bytes / 2;
2465db987421SOswald Buddenhagen fxbus = snd_emu10k1_fxbus;
2466db987421SOswald Buddenhagen extin = emu->audigy ? snd_emu10k1_audigy_ins : snd_emu10k1_sblive_ins;
2467db987421SOswald Buddenhagen extout = emu->audigy ? snd_emu10k1_audigy_outs : snd_emu10k1_sblive_outs;
2468e81995a8SOswald Buddenhagen extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask;
2469e81995a8SOswald Buddenhagen extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask;
24701da177e4SLinus Torvalds for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
2471e81995a8SOswald Buddenhagen copy_string(info->fxbus_names[res], *fxbus, "FXBUS", res);
24721da177e4SLinus Torvalds copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
24731da177e4SLinus Torvalds copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
24741da177e4SLinus Torvalds }
24751da177e4SLinus Torvalds for (res = 16; res < 32; res++, extout++)
24761da177e4SLinus Torvalds copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
24771da177e4SLinus Torvalds info->gpr_controls = emu->fx8010.gpr_count;
24781da177e4SLinus Torvalds }
24791da177e4SLinus Torvalds
snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw,struct file * file,unsigned int cmd,unsigned long arg)2480eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg)
24811da177e4SLinus Torvalds {
2482eb4698f3STakashi Iwai struct snd_emu10k1 *emu = hw->private_data;
2483eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_info *info;
2484eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_code *icode;
2485eb4698f3STakashi Iwai struct snd_emu10k1_fx8010_pcm_rec *ipcm;
24861da177e4SLinus Torvalds unsigned int addr;
24871da177e4SLinus Torvalds void __user *argp = (void __user *)arg;
24881da177e4SLinus Torvalds int res;
24891da177e4SLinus Torvalds
24901da177e4SLinus Torvalds switch (cmd) {
2491f7ba7fc6STakashi Iwai case SNDRV_EMU10K1_IOCTL_PVERSION:
2492f7ba7fc6STakashi Iwai emu->support_tlv = 1;
2493f7ba7fc6STakashi Iwai return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
24941da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_INFO:
249549434c6cSWilly Tarreau info = kzalloc(sizeof(*info), GFP_KERNEL);
24961da177e4SLinus Torvalds if (!info)
24971da177e4SLinus Torvalds return -ENOMEM;
249851882453SMariusz Kozlowski snd_emu10k1_fx8010_info(emu, info);
24991da177e4SLinus Torvalds if (copy_to_user(argp, info, sizeof(*info))) {
25001da177e4SLinus Torvalds kfree(info);
25011da177e4SLinus Torvalds return -EFAULT;
25021da177e4SLinus Torvalds }
25031da177e4SLinus Torvalds kfree(info);
25041da177e4SLinus Torvalds return 0;
25051da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_CODE_POKE:
25061da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25071da177e4SLinus Torvalds return -EPERM;
2508336500f0SLi Zefan
2509336500f0SLi Zefan icode = memdup_user(argp, sizeof(*icode));
2510336500f0SLi Zefan if (IS_ERR(icode))
2511336500f0SLi Zefan return PTR_ERR(icode);
2512d42fe63dSTakashi Iwai res = snd_emu10k1_icode_poke(emu, icode, false);
25131da177e4SLinus Torvalds kfree(icode);
25141da177e4SLinus Torvalds return res;
25151da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
2516336500f0SLi Zefan icode = memdup_user(argp, sizeof(*icode));
2517336500f0SLi Zefan if (IS_ERR(icode))
2518336500f0SLi Zefan return PTR_ERR(icode);
25191da177e4SLinus Torvalds res = snd_emu10k1_icode_peek(emu, icode);
25201da177e4SLinus Torvalds if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) {
25211da177e4SLinus Torvalds kfree(icode);
25221da177e4SLinus Torvalds return -EFAULT;
25231da177e4SLinus Torvalds }
25241da177e4SLinus Torvalds kfree(icode);
25251da177e4SLinus Torvalds return res;
25261da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_PCM_POKE:
2527336500f0SLi Zefan ipcm = memdup_user(argp, sizeof(*ipcm));
2528336500f0SLi Zefan if (IS_ERR(ipcm))
2529336500f0SLi Zefan return PTR_ERR(ipcm);
25301da177e4SLinus Torvalds res = snd_emu10k1_ipcm_poke(emu, ipcm);
25311da177e4SLinus Torvalds kfree(ipcm);
25321da177e4SLinus Torvalds return res;
25331da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_PCM_PEEK:
2534336500f0SLi Zefan ipcm = memdup_user(argp, sizeof(*ipcm));
2535336500f0SLi Zefan if (IS_ERR(ipcm))
2536336500f0SLi Zefan return PTR_ERR(ipcm);
25371da177e4SLinus Torvalds res = snd_emu10k1_ipcm_peek(emu, ipcm);
25381da177e4SLinus Torvalds if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) {
25391da177e4SLinus Torvalds kfree(ipcm);
25401da177e4SLinus Torvalds return -EFAULT;
25411da177e4SLinus Torvalds }
25421da177e4SLinus Torvalds kfree(ipcm);
25431da177e4SLinus Torvalds return res;
25441da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_TRAM_SETUP:
25451da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25461da177e4SLinus Torvalds return -EPERM;
25471da177e4SLinus Torvalds if (get_user(addr, (unsigned int __user *)argp))
25481da177e4SLinus Torvalds return -EFAULT;
254962932df8SIngo Molnar mutex_lock(&emu->fx8010.lock);
25501da177e4SLinus Torvalds res = snd_emu10k1_fx8010_tram_setup(emu, addr);
255162932df8SIngo Molnar mutex_unlock(&emu->fx8010.lock);
25521da177e4SLinus Torvalds return res;
25531da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_STOP:
25541da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25551da177e4SLinus Torvalds return -EPERM;
25561da177e4SLinus Torvalds if (emu->audigy)
25571da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
25581da177e4SLinus Torvalds else
25591da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
25601da177e4SLinus Torvalds return 0;
25611da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_CONTINUE:
25621da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25631da177e4SLinus Torvalds return -EPERM;
25641da177e4SLinus Torvalds if (emu->audigy)
25651da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0);
25661da177e4SLinus Torvalds else
25671da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0);
25681da177e4SLinus Torvalds return 0;
25691da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER:
25701da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25711da177e4SLinus Torvalds return -EPERM;
25721da177e4SLinus Torvalds if (emu->audigy)
25731da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC);
25741da177e4SLinus Torvalds else
25751da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC);
25761da177e4SLinus Torvalds udelay(10);
25771da177e4SLinus Torvalds if (emu->audigy)
25781da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
25791da177e4SLinus Torvalds else
25801da177e4SLinus Torvalds snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
25811da177e4SLinus Torvalds return 0;
25821da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_SINGLE_STEP:
25831da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN))
25841da177e4SLinus Torvalds return -EPERM;
25851da177e4SLinus Torvalds if (get_user(addr, (unsigned int __user *)argp))
25861da177e4SLinus Torvalds return -EFAULT;
258737505289SOswald Buddenhagen if (emu->audigy) {
258837505289SOswald Buddenhagen if (addr > A_DBG_STEP_ADDR)
25891da177e4SLinus Torvalds return -EINVAL;
259037505289SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP);
25911da177e4SLinus Torvalds udelay(10);
259237505289SOswald Buddenhagen snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_STEP | addr);
259337505289SOswald Buddenhagen } else {
259437505289SOswald Buddenhagen if (addr > EMU10K1_DBG_SINGLE_STEP_ADDR)
259537505289SOswald Buddenhagen return -EINVAL;
259637505289SOswald Buddenhagen snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP);
259737505289SOswald Buddenhagen udelay(10);
259837505289SOswald Buddenhagen snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_STEP | addr);
259937505289SOswald Buddenhagen }
26001da177e4SLinus Torvalds return 0;
26011da177e4SLinus Torvalds case SNDRV_EMU10K1_IOCTL_DBG_READ:
26021da177e4SLinus Torvalds if (emu->audigy)
26031da177e4SLinus Torvalds addr = snd_emu10k1_ptr_read(emu, A_DBG, 0);
26041da177e4SLinus Torvalds else
26051da177e4SLinus Torvalds addr = snd_emu10k1_ptr_read(emu, DBG, 0);
26061da177e4SLinus Torvalds if (put_user(addr, (unsigned int __user *)argp))
26071da177e4SLinus Torvalds return -EFAULT;
26081da177e4SLinus Torvalds return 0;
26091da177e4SLinus Torvalds }
26101da177e4SLinus Torvalds return -ENOTTY;
26111da177e4SLinus Torvalds }
26121da177e4SLinus Torvalds
snd_emu10k1_fx8010_release(struct snd_hwdep * hw,struct file * file)2613eb4698f3STakashi Iwai static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
26141da177e4SLinus Torvalds {
26151da177e4SLinus Torvalds return 0;
26161da177e4SLinus Torvalds }
26171da177e4SLinus Torvalds
snd_emu10k1_fx8010_new(struct snd_emu10k1 * emu,int device)2618bb814c39SLars-Peter Clausen int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
26191da177e4SLinus Torvalds {
2620eb4698f3STakashi Iwai struct snd_hwdep *hw;
26211da177e4SLinus Torvalds int err;
26221da177e4SLinus Torvalds
262312bda107STakashi Iwai err = snd_hwdep_new(emu->card, "FX8010", device, &hw);
262412bda107STakashi Iwai if (err < 0)
26251da177e4SLinus Torvalds return err;
26261da177e4SLinus Torvalds strcpy(hw->name, "EMU10K1 (FX8010)");
26271da177e4SLinus Torvalds hw->iface = SNDRV_HWDEP_IFACE_EMU10K1;
26281da177e4SLinus Torvalds hw->ops.open = snd_emu10k1_fx8010_open;
26291da177e4SLinus Torvalds hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
26301da177e4SLinus Torvalds hw->ops.release = snd_emu10k1_fx8010_release;
26311da177e4SLinus Torvalds hw->private_data = emu;
26321da177e4SLinus Torvalds return 0;
26331da177e4SLinus Torvalds }
263409668b44STakashi Iwai
2635c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 * emu)2636e23e7a14SBill Pemberton int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
263709668b44STakashi Iwai {
263809668b44STakashi Iwai int len;
263909668b44STakashi Iwai
264009668b44STakashi Iwai len = emu->audigy ? 0x200 : 0x100;
26416da2ec56SKees Cook emu->saved_gpr = kmalloc_array(len, 4, GFP_KERNEL);
264209668b44STakashi Iwai if (! emu->saved_gpr)
264309668b44STakashi Iwai return -ENOMEM;
264409668b44STakashi Iwai len = emu->audigy ? 0x100 : 0xa0;
26456da2ec56SKees Cook emu->tram_val_saved = kmalloc_array(len, 4, GFP_KERNEL);
26466da2ec56SKees Cook emu->tram_addr_saved = kmalloc_array(len, 4, GFP_KERNEL);
264709668b44STakashi Iwai if (! emu->tram_val_saved || ! emu->tram_addr_saved)
264809668b44STakashi Iwai return -ENOMEM;
264909668b44STakashi Iwai len = emu->audigy ? 2 * 1024 : 2 * 512;
265042bc47b3SKees Cook emu->saved_icode = vmalloc(array_size(len, 4));
265109668b44STakashi Iwai if (! emu->saved_icode)
265209668b44STakashi Iwai return -ENOMEM;
265309668b44STakashi Iwai return 0;
265409668b44STakashi Iwai }
265509668b44STakashi Iwai
snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 * emu)265609668b44STakashi Iwai void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
265709668b44STakashi Iwai {
265809668b44STakashi Iwai kfree(emu->saved_gpr);
265909668b44STakashi Iwai kfree(emu->tram_val_saved);
266009668b44STakashi Iwai kfree(emu->tram_addr_saved);
266109668b44STakashi Iwai vfree(emu->saved_icode);
266209668b44STakashi Iwai }
266309668b44STakashi Iwai
266409668b44STakashi Iwai /*
266509668b44STakashi Iwai * save/restore GPR, TRAM and codes
266609668b44STakashi Iwai */
snd_emu10k1_efx_suspend(struct snd_emu10k1 * emu)266709668b44STakashi Iwai void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
266809668b44STakashi Iwai {
266909668b44STakashi Iwai int i, len;
267009668b44STakashi Iwai
267109668b44STakashi Iwai len = emu->audigy ? 0x200 : 0x100;
267209668b44STakashi Iwai for (i = 0; i < len; i++)
267309668b44STakashi Iwai emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
267409668b44STakashi Iwai
267509668b44STakashi Iwai len = emu->audigy ? 0x100 : 0xa0;
267609668b44STakashi Iwai for (i = 0; i < len; i++) {
267709668b44STakashi Iwai emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
267809668b44STakashi Iwai emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
267909668b44STakashi Iwai if (emu->audigy) {
268009668b44STakashi Iwai emu->tram_addr_saved[i] >>= 12;
268109668b44STakashi Iwai emu->tram_addr_saved[i] |=
268209668b44STakashi Iwai snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
268309668b44STakashi Iwai }
268409668b44STakashi Iwai }
268509668b44STakashi Iwai
268609668b44STakashi Iwai len = emu->audigy ? 2 * 1024 : 2 * 512;
268709668b44STakashi Iwai for (i = 0; i < len; i++)
268809668b44STakashi Iwai emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
268909668b44STakashi Iwai }
269009668b44STakashi Iwai
snd_emu10k1_efx_resume(struct snd_emu10k1 * emu)269109668b44STakashi Iwai void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
269209668b44STakashi Iwai {
269309668b44STakashi Iwai int i, len;
269409668b44STakashi Iwai
269509668b44STakashi Iwai /* set up TRAM */
269609668b44STakashi Iwai if (emu->fx8010.etram_pages.bytes > 0) {
269709668b44STakashi Iwai unsigned size, size_reg = 0;
269809668b44STakashi Iwai size = emu->fx8010.etram_pages.bytes / 2;
269909668b44STakashi Iwai size = (size - 1) >> 13;
270009668b44STakashi Iwai while (size) {
270109668b44STakashi Iwai size >>= 1;
270209668b44STakashi Iwai size_reg++;
270309668b44STakashi Iwai }
270409668b44STakashi Iwai outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
270509668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
270609668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
270709668b44STakashi Iwai outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
270809668b44STakashi Iwai }
270909668b44STakashi Iwai
271009668b44STakashi Iwai if (emu->audigy)
271109668b44STakashi Iwai snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
271209668b44STakashi Iwai else
271309668b44STakashi Iwai snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
271409668b44STakashi Iwai
271509668b44STakashi Iwai len = emu->audigy ? 0x200 : 0x100;
271609668b44STakashi Iwai for (i = 0; i < len; i++)
271709668b44STakashi Iwai snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
271809668b44STakashi Iwai
271909668b44STakashi Iwai len = emu->audigy ? 0x100 : 0xa0;
272009668b44STakashi Iwai for (i = 0; i < len; i++) {
272109668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
272209668b44STakashi Iwai emu->tram_val_saved[i]);
272309668b44STakashi Iwai if (! emu->audigy)
272409668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
272509668b44STakashi Iwai emu->tram_addr_saved[i]);
272609668b44STakashi Iwai else {
272709668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
272809668b44STakashi Iwai emu->tram_addr_saved[i] << 12);
272909668b44STakashi Iwai snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
273009668b44STakashi Iwai emu->tram_addr_saved[i] >> 20);
273109668b44STakashi Iwai }
273209668b44STakashi Iwai }
273309668b44STakashi Iwai
273409668b44STakashi Iwai len = emu->audigy ? 2 * 1024 : 2 * 512;
273509668b44STakashi Iwai for (i = 0; i < len; i++)
273609668b44STakashi Iwai snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
273709668b44STakashi Iwai
273809668b44STakashi Iwai /* start FX processor when the DSP code is updated */
273909668b44STakashi Iwai if (emu->audigy)
274009668b44STakashi Iwai snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
274109668b44STakashi Iwai else
274209668b44STakashi Iwai snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
274309668b44STakashi Iwai }
274409668b44STakashi Iwai #endif
2745