diff options
26 files changed, 2301 insertions, 2332 deletions
diff --git a/Documentation/sound/cards/audigy-mixer.rst b/Documentation/sound/cards/audigy-mixer.rst index aa176451d5b5..ea66b50a2b03 100644 --- a/Documentation/sound/cards/audigy-mixer.rst +++ b/Documentation/sound/cards/audigy-mixer.rst @@ -227,7 +227,7 @@ PCM stream related controls name='EMU10K1 PCM Volume',index 0-31 ------------------------------------ -Channel volume attenuation in range 0-0xffff. The maximum value (no +Channel volume attenuation in range 0-0x1fffd. The middle value (no attenuation) is default. The channel mapping for three values is as follows: @@ -240,30 +240,30 @@ name='EMU10K1 PCM Send Routing',index 0-31 This control specifies the destination - FX-bus accumulators. There are 24 values in this mapping: -* 0 - mono, A destination (FX-bus 0-63), default 0 -* 1 - mono, B destination (FX-bus 0-63), default 1 -* 2 - mono, C destination (FX-bus 0-63), default 2 -* 3 - mono, D destination (FX-bus 0-63), default 3 -* 4 - mono, E destination (FX-bus 0-63), default 0 -* 5 - mono, F destination (FX-bus 0-63), default 0 -* 6 - mono, G destination (FX-bus 0-63), default 0 -* 7 - mono, H destination (FX-bus 0-63), default 0 -* 8 - left, A destination (FX-bus 0-63), default 0 -* 9 - left, B destination (FX-bus 0-63), default 1 +* 0 - mono, A destination (FX-bus 0-63), default 0 +* 1 - mono, B destination (FX-bus 0-63), default 1 +* 2 - mono, C destination (FX-bus 0-63), default 2 +* 3 - mono, D destination (FX-bus 0-63), default 3 +* 4 - mono, E destination (FX-bus 0-63), default 4 +* 5 - mono, F destination (FX-bus 0-63), default 5 +* 6 - mono, G destination (FX-bus 0-63), default 6 +* 7 - mono, H destination (FX-bus 0-63), default 7 +* 8 - left, A destination (FX-bus 0-63), default 0 +* 9 - left, B destination (FX-bus 0-63), default 1 * 10 - left, C destination (FX-bus 0-63), default 2 * 11 - left, D destination (FX-bus 0-63), default 3 -* 12 - left, E destination (FX-bus 0-63), default 0 -* 13 - left, F destination (FX-bus 0-63), default 0 -* 14 - left, G destination (FX-bus 0-63), default 0 -* 15 - left, H destination (FX-bus 0-63), default 0 +* 12 - left, E destination (FX-bus 0-63), default 4 +* 13 - left, F destination (FX-bus 0-63), default 5 +* 14 - left, G destination (FX-bus 0-63), default 6 +* 15 - left, H destination (FX-bus 0-63), default 7 * 16 - right, A destination (FX-bus 0-63), default 0 * 17 - right, B destination (FX-bus 0-63), default 1 * 18 - right, C destination (FX-bus 0-63), default 2 * 19 - right, D destination (FX-bus 0-63), default 3 -* 20 - right, E destination (FX-bus 0-63), default 0 -* 21 - right, F destination (FX-bus 0-63), default 0 -* 22 - right, G destination (FX-bus 0-63), default 0 -* 23 - right, H destination (FX-bus 0-63), default 0 +* 20 - right, E destination (FX-bus 0-63), default 4 +* 21 - right, F destination (FX-bus 0-63), default 5 +* 22 - right, G destination (FX-bus 0-63), default 6 +* 23 - right, H destination (FX-bus 0-63), default 7 Don't forget that it's illegal to assign a channel to the same FX-bus accumulator more than once (it means 0=0 && 1=0 is an invalid combination). diff --git a/Documentation/sound/cards/sb-live-mixer.rst b/Documentation/sound/cards/sb-live-mixer.rst index 819886634400..4dd9bfe01bd8 100644 --- a/Documentation/sound/cards/sb-live-mixer.rst +++ b/Documentation/sound/cards/sb-live-mixer.rst @@ -258,7 +258,7 @@ PCM stream related controls ``name='EMU10K1 PCM Volume',index 0-31`` ---------------------------------------- -Channel volume attenuation in range 0-0xffff. The maximum value (no +Channel volume attenuation in range 0-0x1fffd. The middle value (no attenuation) is default. The channel mapping for three values is as follows: diff --git a/include/sound/core.h b/include/sound/core.h index 3edc4ab08774..4ea5f66b59d7 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -98,7 +98,7 @@ struct snd_card { struct device ctl_dev; /* control device */ unsigned int last_numid; /* last used numeric ID */ - struct rw_semaphore controls_rwsem; /* controls list lock */ + struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ rwlock_t ctl_files_rwlock; /* ctl_files list lock */ int controls_count; /* count of all controls */ size_t user_ctl_alloc_size; // current memory allocation by user controls. diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 8fe80dcee71b..164a2374b4c2 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -38,6 +38,35 @@ #define IP_TO_CP(ip) ((ip == 0) ? 0 : (((0x00001000uL | (ip & 0x00000FFFL)) << (((ip >> 12) & 0x000FL) + 4)) & 0xFFFF0000uL)) +// This is used to define hardware bit-fields (sub-registers) by combining +// the bit shift and count with the actual register address. The passed +// mask must represent a single run of adjacent bits. +// The non-concatenating (_NC) variant should be used directly only for +// sub-registers that do not follow the <register>_<field> naming pattern. +#define SUB_REG_NC(reg, field, mask) \ + enum { \ + field ## _MASK = mask, \ + field = reg | \ + (__builtin_ctz(mask) << 16) | \ + (__builtin_popcount(mask) << 24), \ + }; +#define SUB_REG(reg, field, mask) SUB_REG_NC(reg, reg ## _ ## field, mask) + +// Macros for manipulating values of bit-fields declared using the above macros. +// Best used with constant register addresses, as otherwise quite some code is +// generated. The actual register read/write functions handle combined addresses +// automatically, so use of these macros conveys no advantage when accessing a +// single sub-register at a time. +#define REG_SHIFT(r) (((r) >> 16) & 0x1f) +#define REG_SIZE(r) (((r) >> 24) & 0x1f) +#define REG_MASK0(r) ((1U << REG_SIZE(r)) - 1U) +#define REG_MASK(r) (REG_MASK0(r) << REG_SHIFT(r)) +#define REG_VAL_GET(r, v) ((v & REG_MASK(r)) >> REG_SHIFT(r)) +#define REG_VAL_PUT(r, v) ((v) << REG_SHIFT(r)) + +// List terminator for snd_emu10k1_ptr_write_multiple() +#define REGLIST_END ~0 + // Audigy specify registers are prefixed with 'A_' /************************************************************************************************/ @@ -90,6 +119,10 @@ #define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */ #define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */ #define IPR_CHANNELLOOP 0x00000040 /* Channel (half) loop interrupt(s) pending */ + /* The interrupt is triggered shortly after */ + /* CCR_READADDRESS has crossed the boundary; */ + /* due to the cache, this runs ahead of the */ + /* actual playback position. */ #define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */ /* highest set channel in CLIPL, CLIPH, HLIPL, */ /* or HLIPH. When IPR is written with CL set, */ @@ -148,12 +181,10 @@ #define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */ #define WC 0x10 /* Wall Clock register */ -#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */ -#define WC_SAMPLECOUNTER 0x14060010 -#define WC_CURRENTCHANNEL_MASK 0x0000003F /* Channel [0..63] currently being serviced */ +SUB_REG(WC, SAMPLECOUNTER, 0x03FFFFC0) /* Sample periods elapsed since reset */ +SUB_REG(WC, CURRENTCHANNEL, 0x0000003F) /* Channel [0..63] currently being serviced */ /* NOTE: Each channel takes 1/64th of a sample */ /* period to be serviced. */ -#define WC_CURRENTCHANNEL 0x06000010 #define HCFG 0x14 /* Hardware config register */ /* NOTE: There is no reason to use the legacy */ @@ -225,9 +256,8 @@ /* async audio source */ #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ /* NOTE: This should generally never be used. */ -#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */ +SUB_REG(HCFG, LOCKTANKCACHE, 0x00000004) /* 1 = Cancel bustmaster accesses to tankcache */ /* NOTE: This should generally never be used. */ -#define HCFG_LOCKTANKCACHE 0x01020014 #define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */ /* NOTE: This is a 'cheap' way to implement a */ /* master mute function on the mute button, and */ @@ -381,56 +411,49 @@ // distortion), the modulation engine sets the target registers, towards // which the current registers "swerve" gradually. +// For the odd channel in a stereo pair, these registers are meaningless: +// CPF_STEREO, CPF_CURRENTPITCH, PTRX_PITCHTARGET, CCR_CACHEINVALIDSIZE, +// PSST_LOOPSTARTADDR, DSL_LOOPENDADDR, CCCA_CURRADDR +// The somewhat non-obviously still meaningful ones are: +// CPF_STOP, CPF_FRACADDRESS, CCR_READADDRESS (!), +// CCCA_INTERPROM, CCCA_8BITSELECT (!) +// (The envelope engine is ignored here, as stereo matters only for verbatim playback.) + #define CPF 0x00 /* Current pitch and fraction register */ -#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */ -#define CPF_CURRENTPITCH 0x10100000 +SUB_REG(CPF, CURRENTPITCH, 0xffff0000) /* Current pitch (linear, 0x4000 == unity pitch shift) */ #define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */ -#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */ +SUB_REG(CPF, STOP, 0x00004000) /* 1 = Current pitch forced to 0 */ + /* Can be set only while matching bit in SOLEx is 1 */ #define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */ #define PTRX 0x01 /* Pitch target and send A/B amounts register */ -#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */ -#define PTRX_PITCHTARGET 0x10100001 -#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */ -#define PTRX_FXSENDAMOUNT_A 0x08080001 -#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */ -#define PTRX_FXSENDAMOUNT_B 0x08000001 +SUB_REG(PTRX, PITCHTARGET, 0xffff0000) /* Pitch target of specified channel */ +SUB_REG(PTRX, FXSENDAMOUNT_A, 0x0000ff00) /* Linear level of channel output sent to FX send bus A */ +SUB_REG(PTRX, FXSENDAMOUNT_B, 0x000000ff) /* Linear level of channel output sent to FX send bus B */ +// Note: the volumes are raw multpliers, so real 100% is impossible. #define CVCF 0x02 /* Current volume and filter cutoff register */ -#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */ -#define CVCF_CURRENTVOL 0x10100002 -#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */ -#define CVCF_CURRENTFILTER 0x10000002 +SUB_REG(CVCF, CURRENTVOL, 0xffff0000) /* Current linear volume of specified channel */ +SUB_REG(CVCF, CURRENTFILTER, 0x0000ffff) /* Current filter cutoff frequency of specified channel */ #define VTFT 0x03 /* Volume target and filter cutoff target register */ -#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */ -#define VTFT_VOLUMETARGET 0x10100003 -#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */ -#define VTFT_FILTERTARGET 0x10000003 +SUB_REG(VTFT, VOLUMETARGET, 0xffff0000) /* Volume target of specified channel */ +SUB_REG(VTFT, FILTERTARGET, 0x0000ffff) /* Filter cutoff target of specified channel */ #define Z1 0x05 /* Filter delay memory 1 register */ #define Z2 0x04 /* Filter delay memory 2 register */ #define PSST 0x06 /* Send C amount and loop start address register */ -#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */ - -#define PSST_FXSENDAMOUNT_C 0x08180006 - -#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */ -#define PSST_LOOPSTARTADDR 0x18000006 +SUB_REG(PSST, FXSENDAMOUNT_C, 0xff000000) /* Linear level of channel output sent to FX send bus C */ +SUB_REG(PSST, LOOPSTARTADDR, 0x00ffffff) /* Loop start address of the specified channel */ #define DSL 0x07 /* Send D amount and loop end address register */ -#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */ - -#define DSL_FXSENDAMOUNT_D 0x08180007 - -#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */ -#define DSL_LOOPENDADDR 0x18000007 +SUB_REG(DSL, FXSENDAMOUNT_D, 0xff000000) /* Linear level of channel output sent to FX send bus D */ +SUB_REG(DSL, LOOPENDADDR, 0x00ffffff) /* Loop end address of the specified channel */ #define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */ -#define CCCA_RESONANCE_MASK 0xf0000000 /* Lowpass filter resonance (Q) height */ -#define CCCA_RESONANCE 0x041c0008 +SUB_REG(CCCA, RESONANCE, 0xf0000000) /* Lowpass filter resonance (Q) height */ #define CCCA_INTERPROM_MASK 0x0e000000 /* Selects passband of interpolation ROM */ /* 1 == full band, 7 == lowpass */ /* ROM 0 is used when pitch shifting downward or less */ @@ -447,27 +470,24 @@ #define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */ #define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */ /* 8-bit samples are unsigned, 16-bit ones signed */ -#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */ -#define CCCA_CURRADDR 0x18000008 +SUB_REG(CCCA, CURRADDR, 0x00ffffff) /* Current address of the selected channel */ #define CCR 0x09 /* Cache control register */ -#define CCR_CACHEINVALIDSIZE 0x07190009 -#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples before the read address */ +SUB_REG(CCR, CACHEINVALIDSIZE, 0xfe000000) /* Number of invalid samples before the read address */ #define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */ #define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */ /* Auto-set from CPF_STEREO_MASK */ #define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */ /* Auto-set from CCCA_8BITSELECT */ -#define CCR_READADDRESS 0x06100009 -#define CCR_READADDRESS_MASK 0x003f0000 /* Next cached sample to play */ -#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */ +SUB_REG(CCR, READADDRESS, 0x003f0000) /* Next cached sample to play */ +SUB_REG(CCR, LOOPINVALSIZE, 0x0000fe00) /* Number of invalid samples in cache prior to loop */ /* NOTE: This is valid only if CACHELOOPFLAG is set */ #define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */ -#define CCR_CACHELOOPADDRHI 0x000000ff /* CLP_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ +SUB_REG(CCR, CACHELOOPADDRHI, 0x000000ff) /* CLP_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */ #define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */ /* NOTE: This register is normally not used */ -#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address low word */ +SUB_REG(CLP, CACHELOOPADDR, 0x0000ffff) /* Cache loop address low word */ #define FXRT 0x0b /* Effects send routing register */ /* NOTE: It is illegal to assign the same routing to */ @@ -537,20 +557,17 @@ #define IP_UNITY 0x0000e000 /* Unity pitch shift */ #define IFATN 0x19 /* Initial filter cutoff and attenuation register */ -#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */ +SUB_REG(IFATN, FILTERCUTOFF, 0x0000ff00) /* Initial filter cutoff frequency in exponential units */ /* 6 most significant bits are semitones */ /* 2 least significant bits are fractions */ -#define IFATN_FILTERCUTOFF 0x08080019 -#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */ -#define IFATN_ATTENUATION 0x08000019 +SUB_REG(IFATN, ATTENUATION, 0x000000ff) /* Initial attenuation in 0.375dB steps */ #define PEFE 0x1a /* Pitch envelope and filter envelope amount register */ -#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */ +SUB_REG(PEFE, PITCHAMOUNT, 0x0000ff00) /* Pitch envlope amount */ /* Signed 2's complement, +/- one octave peak extremes */ -#define PEFE_PITCHAMOUNT 0x0808001a -#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */ +SUB_REG(PEFE, FILTERAMOUNT, 0x000000ff) /* Filter envlope amount */ /* Signed 2's complement, +/- six octaves peak extremes */ -#define PEFE_FILTERAMOUNT 0x0800001a + #define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */ #define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */ @@ -577,24 +594,22 @@ /* 0x1f: not used */ -#define CD0 0x20 /* Cache data 0 register */ -#define CD1 0x21 /* Cache data 1 register */ -#define CD2 0x22 /* Cache data 2 register */ -#define CD3 0x23 /* Cache data 3 register */ -#define CD4 0x24 /* Cache data 4 register */ -#define CD5 0x25 /* Cache data 5 register */ -#define CD6 0x26 /* Cache data 6 register */ -#define CD7 0x27 /* Cache data 7 register */ -#define CD8 0x28 /* Cache data 8 register */ -#define CD9 0x29 /* Cache data 9 register */ -#define CDA 0x2a /* Cache data A register */ -#define CDB 0x2b /* Cache data B register */ -#define CDC 0x2c /* Cache data C register */ -#define CDD 0x2d /* Cache data D register */ -#define CDE 0x2e /* Cache data E register */ -#define CDF 0x2f /* Cache data F register */ - -/* 0x30-3f seem to be the same as 0x20-2f */ +// 32 cache registers (== 128 bytes) per channel follow. +// In stereo mode, the two channels' caches are concatenated into one, +// and hold the interleaved frames. +// The cache holds 64 frames, so the upper half is not used in 8-bit mode. +// All registers mentioned below count in frames. +// The cache is a ring buffer; CCR_READADDRESS operates modulo 64. +// The cache is filled from (CCCA_CURRADDR - CCR_CACHEINVALIDSIZE) +// into (CCR_READADDRESS - CCR_CACHEINVALIDSIZE). +// The engine has a fetch threshold of 32 bytes, so it tries to keep +// CCR_CACHEINVALIDSIZE below 8 (16-bit stereo), 16 (16-bit mono, +// 8-bit stereo), or 32 (8-bit mono). The actual transfers are pretty +// unpredictable, especially if several voices are running. +// Frames are consumed at CCR_READADDRESS, which is incremented afterwards, +// along with CCCA_CURRADDR and CCR_CACHEINVALIDSIZE. This implies that the +// actual playback position always lags CCCA_CURRADDR by exactly 64 frames. +#define CD0 0x20 /* Cache data registers 0 .. 0x1f */ #define PTB 0x40 /* Page table base register */ #define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */ @@ -695,6 +710,8 @@ #define ADCBS_BUFSIZE_57344 0x0000001e #define ADCBS_BUFSIZE_65536 0x0000001f +// On Audigy, the FX send amounts are not applied instantly, but determine +// targets towards which the following registers swerve gradually. #define A_CSBA 0x4c /* FX send B & A current amounts */ #define A_CSDC 0x4d /* FX send D & C current amounts */ #define A_CSFE 0x4e /* FX send F & E current amounts */ @@ -755,6 +772,9 @@ #define CLIPL 0x5a /* Channel loop interrupt pending low register */ #define CLIPH 0x5b /* Channel loop interrupt pending high register */ +// These cause CPF_STOP_MASK to be set shortly after CCCA_CURRADDR passes DSL_LOOPENDADDR. +// Subsequent changes to the address registers don't resume; clearing the bit here or in CPF does. +// The registers are NOT synchronized; the next serviced channel picks up immediately. #define SOLEL 0x5c /* Stop on loop enable low register */ #define SOLEH 0x5d /* Stop on loop enable high register */ @@ -793,22 +813,19 @@ #define SRCS_SPDIFRATE_96 0x00080000 #define MICIDX 0x63 /* Microphone recording buffer index register */ -#define MICIDX_MASK 0x0000ffff /* 16-bit value */ -#define MICIDX_IDX 0x10000063 +SUB_REG(MICIDX, IDX, 0x0000ffff) #define ADCIDX 0x64 /* ADC recording buffer index register */ -#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */ -#define ADCIDX_IDX 0x10000064 +SUB_REG(ADCIDX, IDX, 0x0000ffff) #define A_ADCIDX 0x63 -#define A_ADCIDX_IDX 0x10000063 +SUB_REG(A_ADCIDX, IDX, 0x0000ffff) #define A_MICIDX 0x64 -#define A_MICIDX_IDX 0x10000064 +SUB_REG(A_MICIDX, IDX, 0x0000ffff) #define FXIDX 0x65 /* FX recording buffer index register */ -#define FXIDX_MASK 0x0000ffff /* 16-bit value */ -#define FXIDX_IDX 0x10000065 +SUB_REG(FXIDX, IDX, 0x0000ffff) /* The 32-bit HLIEx and HLIPx registers all have one bit per channel control/status */ #define HLIEL 0x66 /* Channel half loop interrupt enable low register */ @@ -852,8 +869,8 @@ #define A_SPDIF_44100 0x00000080 #define A_SPDIF_MUTED 0x000000c0 -#define A_I2S_CAPTURE_RATE_MASK 0x00000e00 /* This sets the capture PCM rate, but it is */ -#define A_I2S_CAPTURE_RATE 0x03090076 /* unclear if this sets the ADC rate as well. */ +SUB_REG_NC(A_EHC, A_I2S_CAPTURE_RATE, 0x00000e00) /* This sets the capture PCM rate, but it is */ + /* unclear if this sets the ADC rate as well. */ #define A_I2S_CAPTURE_48000 0x0 #define A_I2S_CAPTURE_192000 0x1 #define A_I2S_CAPTURE_96000 0x2 @@ -1189,9 +1206,10 @@ * physical outputs of Hana, or outputs going to Alice2/Tina for capture - * 16 x EMU_DST_ALICE2_EMU32_X (2x on rev2 boards). Which data is fed into * a channel depends on the mixer control setting for each destination - see - * emumixer.c - snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[] + * the register arrays in emumixer.c. */ #define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */ + /* This channel is delayed by one sample. */ #define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */ #define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */ #define EMU_DST_ALICE2_EMU32_3 0x0002 /* 16 EMU32 channels to Alice2 +0 to +0xf */ @@ -1425,21 +1443,22 @@ /* ------------------- STRUCTURES -------------------- */ enum { + EMU10K1_UNUSED, // This must be zero EMU10K1_EFX, + EMU10K1_EFX_IRQ, EMU10K1_PCM, + EMU10K1_PCM_IRQ, EMU10K1_SYNTH, - EMU10K1_MIDI + EMU10K1_NUM_TYPES }; struct snd_emu10k1; struct snd_emu10k1_voice { - int number; - unsigned int use: 1, - pcm: 1, - efx: 1, - synth: 1, - midi: 1; + unsigned char number; + unsigned char use; + unsigned char dirty; + unsigned char last; void (*interrupt)(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice); struct snd_emu10k1_pcm *epcm; @@ -1461,6 +1480,7 @@ struct snd_emu10k1_pcm { struct snd_emu10k1_voice *extra; unsigned short running; unsigned short first_ptr; + snd_pcm_uframes_t resume_pos; struct snd_util_memblk *memblk; unsigned int start_addr; unsigned int ccca_start_addr; @@ -1479,6 +1499,8 @@ struct snd_emu10k1_pcm_mixer { /* mono, left, right x 8 sends (4 on emu10k1) */ unsigned char send_routing[3][8]; unsigned char send_volume[3][8]; + // 0x8000 is neutral. The mixer code rescales it to 0xffff to maintain + // backwards compatibility with user space. unsigned short attn[3]; struct snd_emu10k1_pcm *epcm; }; @@ -1492,6 +1514,9 @@ struct snd_emu10k1_pcm_mixer { #define snd_emu10k1_compose_audigy_fxrt2(route) \ ((unsigned int)route[4] | ((unsigned int)route[5] << 8) | ((unsigned int)route[6] << 16) | ((unsigned int)route[7] << 24)) +#define snd_emu10k1_compose_audigy_sendamounts(vol) \ +(((unsigned int)vol[4] << 24) | ((unsigned int)vol[5] << 16) | ((unsigned int)vol[6] << 8) | (unsigned int)vol[7]) + struct snd_emu10k1_memblk { struct snd_util_memblk mem; /* private part */ @@ -1510,9 +1535,9 @@ struct snd_emu10k1_fx8010_ctl { unsigned int vcount; unsigned int count; /* count of GPR (1..16) */ unsigned short gpr[32]; /* GPR number(s) */ - unsigned int value[32]; - unsigned int min; /* minimum range */ - unsigned int max; /* maximum range */ + int value[32]; + int min; /* minimum range */ + int max; /* maximum range */ unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ struct snd_kcontrol *kcontrol; }; @@ -1600,32 +1625,37 @@ struct snd_emu_chip_details { u32 device; u32 subsystem; unsigned char revision; - unsigned char emu10k1_chip; /* Original SB Live. Not SB Live 24bit. */ - /* Redundant with emu10k2_chip being unset. */ - unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ - unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ - /* Redundant with ca0108_chip being unset. */ - unsigned char ca0108_chip; /* Audigy 2 Value */ - unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */ - unsigned char ca0151_chip; /* P16V */ - unsigned char spk71; /* Has 7.1 speakers */ - unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ - unsigned char spdif_bug; /* Has Spdif phasing bug */ - unsigned char ac97_chip; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ - unsigned char ecard; /* APS EEPROM */ - unsigned char emu_model; /* EMU model type */ - unsigned char spi_dac; /* SPI interface for DAC; requires ca0108_chip */ - unsigned char i2c_adc; /* I2C interface for ADC; requires ca0108_chip */ - unsigned char adc_1361t; /* Use Philips 1361T ADC */ - unsigned char invert_shared_spdif; /* analog/digital switch inverted */ + unsigned char emu_model; /* EMU model type */ + unsigned int emu10k1_chip:1; /* Original SB Live. Not SB Live 24bit. */ + /* Redundant with emu10k2_chip being unset. */ + unsigned int emu10k2_chip:1; /* Audigy 1 or Audigy 2. */ + unsigned int ca0102_chip:1; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ + /* Redundant with ca0108_chip being unset. */ + unsigned int ca0108_chip:1; /* Audigy 2 Value */ + unsigned int ca_cardbus_chip:1; /* Audigy 2 ZS Notebook */ + unsigned int ca0151_chip:1; /* P16V */ + unsigned int spk20:1; /* Stereo only */ + unsigned int spk71:1; /* Has 7.1 speakers */ + unsigned int no_adat:1; /* Has no ADAT, only SPDIF */ + unsigned int sblive51:1; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ + unsigned int spdif_bug:1; /* Has Spdif phasing bug */ + unsigned int ac97_chip:2; /* Has an AC97 chip: 1 = mandatory, 2 = optional */ + unsigned int ecard:1; /* APS EEPROM */ + unsigned int spi_dac:1; /* SPI interface for DAC; requires ca0108_chip */ + unsigned int i2c_adc:1; /* I2C interface for ADC; requires ca0108_chip */ + unsigned int adc_1361t:1; /* Use Philips 1361T ADC */ + unsigned int invert_shared_spdif:1; /* analog/digital switch inverted */ const char *driver; const char *name; const char *id; /* for backward compatibility - can be NULL if not needed */ }; +#define NUM_OUTPUT_DESTS 28 +#define NUM_INPUT_DESTS 22 + struct snd_emu1010 { - unsigned int output_source[64]; - unsigned int input_source[64]; + unsigned char output_source[NUM_OUTPUT_DESTS]; + unsigned char input_source[NUM_INPUT_DESTS]; unsigned int adc_pads; /* bit mask */ unsigned int dac_pads; /* bit mask */ unsigned int internal_clock; /* 44100 or 48000 */ @@ -1653,7 +1683,6 @@ struct snd_emu10k1 { unsigned int address_mode; /* address mode */ unsigned long dma_mask; /* PCI DMA mask */ bool iommu_workaround; /* IOMMU workaround needed */ - unsigned int delay_pcm_irq; /* in samples */ int max_cache_pages; /* max memory size / PAGE_SIZE */ struct snd_dma_buffer silent_page; /* silent page */ struct snd_dma_buffer ptb_pages; /* page table pages */ @@ -1775,6 +1804,7 @@ int snd_emu10k1_done(struct snd_emu10k1 * emu); /* I/O functions */ unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn); void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); +void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, ...); unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn); void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data); int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int data); @@ -1791,13 +1821,17 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum); void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum); void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum); void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum); +#if 0 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum); void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum); +#endif +void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices); +void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices); +int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices); void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait); static inline unsigned int snd_emu10k1_wc(struct snd_emu10k1 *emu) { return (inl(emu->port + WC) >> 6) & 0xfffff; } unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg); void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data); -unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate); #ifdef CONFIG_PM_SLEEP void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu); @@ -1825,7 +1859,8 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk); /* voice allocation */ -int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int pair, struct snd_emu10k1_voice **rvoice); +int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels, + struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice); int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice); /* MIDI uart */ diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 5c5f41dd4001..409069b519fe 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -274,6 +274,7 @@ typedef int __bitwise snd_pcm_subformat_t; #define SNDRV_PCM_INFO_DOUBLE 0x00000004 /* Double buffering needed for PCM start/stop */ #define SNDRV_PCM_INFO_BATCH 0x00000010 /* double buffering */ #define SNDRV_PCM_INFO_SYNC_APPLPTR 0x00000020 /* need the explicit sync of appl_ptr update */ +#define SNDRV_PCM_INFO_PERFECT_DRAIN 0x00000040 /* silencing at the end of stream is not required */ #define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 /* channels are interleaved */ #define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 /* channels are not interleaved */ #define SNDRV_PCM_INFO_COMPLEX 0x00000400 /* complex frame organization (mmap only) */ @@ -383,6 +384,9 @@ typedef int snd_pcm_hw_param_t; #define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) /* avoid rate resampling */ #define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) /* export buffer */ #define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) /* disable period wakeups */ +#define SNDRV_PCM_HW_PARAMS_NO_DRAIN_SILENCE (1<<3) /* suppress drain with the filling + * of the silence samples + */ struct snd_interval { unsigned int min, max; diff --git a/include/uapi/sound/emu10k1.h b/include/uapi/sound/emu10k1.h index c8e131d6da00..4c32a116e7ad 100644 --- a/include/uapi/sound/emu10k1.h +++ b/include/uapi/sound/emu10k1.h @@ -308,6 +308,8 @@ struct snd_emu10k1_fx8010_info { #define EMU10K1_GPR_TRANSLATION_BASS 2 #define EMU10K1_GPR_TRANSLATION_TREBLE 3 #define EMU10K1_GPR_TRANSLATION_ONOFF 4 +#define EMU10K1_GPR_TRANSLATION_NEGATE 5 +#define EMU10K1_GPR_TRANSLATION_NEG_TABLE100 6 enum emu10k1_ctl_elem_iface { EMU10K1_CTL_ELEM_IFACE_MIXER = 2, /* virtual mixer device */ @@ -328,9 +330,9 @@ struct snd_emu10k1_fx8010_control_gpr { unsigned int vcount; /* visible count */ unsigned int count; /* count of GPR (1..16) */ unsigned short gpr[32]; /* GPR number(s) */ - unsigned int value[32]; /* initial values */ - unsigned int min; /* minimum range */ - unsigned int max; /* maximum range */ + int value[32]; /* initial values */ + int min; /* minimum range */ + int max; /* maximum range */ unsigned int translation; /* translation type (EMU10K1_GPR_TRANSLATION*) */ const unsigned int *tlv; }; diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index d8a86d1a99d6..9cae5d74335c 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -197,7 +197,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, return err; } -static int get_elem_size(int type, int count) +static int get_elem_size(snd_ctl_elem_type_t type, int count) { switch (type) { case SNDRV_CTL_ELEM_TYPE_INTEGER64: @@ -234,8 +234,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, if (type < 0) return type; - if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || - type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { s32 __user *intp = valuep; int val; @@ -244,7 +244,7 @@ static int copy_ctl_value_from_user(struct snd_card *card, data->value.integer.value[i] = val; } } else { - size = get_elem_size(type, count); + size = get_elem_size((__force snd_ctl_elem_type_t)type, count); if (size < 0) { dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); return -EINVAL; @@ -267,8 +267,8 @@ static int copy_ctl_value_to_user(void __user *userdata, struct snd_ctl_elem_value32 __user *data32 = userdata; int i, size; - if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || - type == SNDRV_CTL_ELEM_TYPE_INTEGER) { + if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN || + type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { s32 __user *intp = valuep; int val; @@ -277,7 +277,7 @@ static int copy_ctl_value_to_user(void __user *userdata, return -EFAULT; } } else { - size = get_elem_size(type, count); + size = get_elem_size((__force snd_ctl_elem_type_t)type, count); if (copy_to_user(valuep, data->value.bytes.data, size)) return -EFAULT; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 39a65d1415ab..95fc56e403b1 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1605,10 +1605,6 @@ static int snd_pcm_do_pause(struct snd_pcm_substream *substream, { if (substream->runtime->trigger_master != substream) return 0; - /* some drivers might use hw_ptr to recover from the pause - - update the hw_ptr now */ - if (pause_pushed(state)) - snd_pcm_update_hw_ptr(substream); /* The jiffies check in snd_pcm_update_hw_ptr*() is done by * a delta between the current jiffies, this gives a large enough * delta, effectively to skip the check once. diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index be3009746f3a..864991d8776d 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -128,6 +128,7 @@ config SND_VIRMIDI config SND_MTPAV tristate "MOTU MidiTimePiece AV multiport MIDI" + depends on HAS_IOPORT select SND_RAWMIDI help To use a MOTU MidiTimePiece AV multiport MIDI adapter @@ -152,6 +153,7 @@ config SND_MTS64 config SND_SERIAL_U16550 tristate "UART16550 serial MIDI driver" + depends on HAS_IOPORT select SND_RAWMIDI help To include support for MIDI serial port interfaces, say Y here @@ -185,6 +187,7 @@ config SND_SERIAL_GENERIC config SND_MPU401 tristate "Generic MPU-401 UART driver" + depends on HAS_IOPORT select SND_MPU401_UART help Say Y here to include support for MIDI ports compatible with diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 6ffa48dd5983..f8159179e38d 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -23,6 +23,7 @@ menuconfig SND_ISA bool "ISA sound devices" depends on ISA || COMPILE_TEST depends on ISA_DMA_API + depends on HAS_IOPORT default y help Support for sound devices connected via the ISA bus. diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 861958451ef5..787868c9e91b 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -26,7 +26,7 @@ config SND_ALS300 select SND_PCM select SND_AC97_CODEC select SND_OPL3_LIB - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+ @@ -36,6 +36,7 @@ config SND_ALS300 config SND_ALS4000 tristate "Avance Logic ALS4000" depends on ISA_DMA_API + depends on HAS_IOPORT select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -51,7 +52,7 @@ config SND_ALI5451 tristate "ALi M5451 PCI Audio Controller" select SND_MPU401_UART select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for the integrated AC97 sound device on motherboards using the ALi M5451 Audio Controller @@ -96,6 +97,7 @@ config SND_ATIIXP_MODEM config SND_AU8810 tristate "Aureal Advantage" + depends on HAS_IOPORT select SND_MPU401_UART select SND_AC97_CODEC help @@ -110,6 +112,7 @@ config SND_AU8810 config SND_AU8820 tristate "Aureal Vortex" + depends on HAS_IOPORT select SND_MPU401_UART select SND_AC97_CODEC help @@ -123,6 +126,7 @@ config SND_AU8820 config SND_AU8830 tristate "Aureal Vortex 2" + depends on HAS_IOPORT select SND_MPU401_UART select SND_AC97_CODEC help @@ -157,7 +161,7 @@ config SND_AZT3328 select SND_RAWMIDI select SND_AC97_CODEC select SND_TIMER - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for Aztech AZF3328 (PCI168) soundcards. @@ -193,6 +197,7 @@ config SND_BT87X_OVERCLOCK config SND_CA0106 tristate "SB Audigy LS / Live 24bit" + depends on HAS_IOPORT select SND_AC97_CODEC select SND_RAWMIDI select SND_VMASTER @@ -205,6 +210,7 @@ config SND_CA0106 config SND_CMIPCI tristate "C-Media 8338, 8738, 8768, 8770" + depends on HAS_IOPORT select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM @@ -221,6 +227,7 @@ config SND_OXYGEN_LIB config SND_OXYGEN tristate "C-Media 8786, 8787, 8788 (Oxygen)" + depends on HAS_IOPORT select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART @@ -246,6 +253,7 @@ config SND_OXYGEN config SND_CS4281 tristate "Cirrus Logic (Sound Fusion) CS4281" + depends on HAS_IOPORT select SND_OPL3_LIB select SND_RAWMIDI select SND_AC97_CODEC @@ -257,6 +265,7 @@ config SND_CS4281 config SND_CS46XX tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" + depends on HAS_IOPORT select SND_RAWMIDI select SND_AC97_CODEC select FW_LOADER @@ -290,6 +299,7 @@ config SND_CS5530 config SND_CS5535AUDIO tristate "CS5535/CS5536 Audio" depends on X86_32 || MIPS || COMPILE_TEST + depends on HAS_IOPORT select SND_PCM select SND_AC97_CODEC help @@ -307,6 +317,7 @@ config SND_CS5535AUDIO config SND_CTXFI tristate "Creative Sound Blaster X-Fi" + depends on HAS_IOPORT select SND_PCM help If you want to use soundcards based on Creative Sound Blastr X-Fi @@ -468,7 +479,7 @@ config SND_EMU10K1 select SND_AC97_CODEC select SND_TIMER select SND_SEQ_DEVICE if SND_SEQUENCER != n - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y to include support for Sound Blaster PCI 512, Live!, Audigy and E-MU APS/0404/1010/1212/1616/1820 soundcards. @@ -491,7 +502,7 @@ config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" select SND_AC97_CODEC select SND_RAWMIDI - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for the Dell OEM version of the Sound Blaster Live!. @@ -501,6 +512,7 @@ config SND_EMU10K1X config SND_ENS1370 tristate "(Creative) Ensoniq AudioPCI 1370" + depends on HAS_IOPORT select SND_RAWMIDI select SND_PCM help @@ -511,6 +523,7 @@ config SND_ENS1370 config SND_ENS1371 tristate "(Creative) Ensoniq AudioPCI 1371/1373" + depends on HAS_IOPORT select SND_RAWMIDI select SND_AC97_CODEC help @@ -525,7 +538,7 @@ config SND_ES1938 select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on ESS Solo-1 (ES1938, ES1946, ES1969) chips. @@ -537,7 +550,7 @@ config SND_ES1968 tristate "ESS ES1968/1978 (Maestro-1/2/2E)" select SND_MPU401_UART select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on ESS Maestro 1/2/2E chips. @@ -569,6 +582,7 @@ config SND_ES1968_RADIO config SND_FM801 tristate "ForteMedia FM801" + depends on HAS_IOPORT select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC @@ -624,7 +638,7 @@ config SND_ICE1712 select SND_MPU401_UART select SND_AC97_CODEC select BITREVERSE - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. @@ -640,6 +654,7 @@ config SND_ICE1712 config SND_ICE1724 tristate "ICE/VT1724/1720 (Envy24HT/PT)" + depends on HAS_IOPORT select SND_RAWMIDI select SND_AC97_CODEC select SND_VMASTER @@ -712,7 +727,7 @@ config SND_LX6464ES config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on ESS Maestro 3 (Allegro) chips. @@ -753,6 +768,7 @@ config SND_NM256 config SND_PCXHR tristate "Digigram PCXHR" + depends on HAS_IOPORT select FW_LOADER select SND_PCM select SND_HWDEP @@ -764,6 +780,7 @@ config SND_PCXHR config SND_RIPTIDE tristate "Conexant Riptide" + depends on HAS_IOPORT select FW_LOADER select SND_OPL3_LIB select SND_MPU401_UART @@ -808,6 +825,7 @@ config SND_RME9652 config SND_SE6X tristate "Studio Evolution SE6X" depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict + depends on HAS_IOPORT select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART @@ -830,7 +848,7 @@ config SND_SONICVIBES select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on the S3 SonicVibes chip. @@ -842,7 +860,7 @@ config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" select SND_MPU401_UART select SND_AC97_CODEC - depends on ZONE_DMA + depends on ZONE_DMA && HAS_IOPORT help Say Y here to include support for soundcards based on Trident 4D-Wave DX/NX or SiS 7018 chips. @@ -852,6 +870,7 @@ config SND_TRIDENT config SND_VIA82XX tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" + depends on HAS_IOPORT select SND_MPU401_UART select SND_AC97_CODEC help @@ -863,6 +882,7 @@ config SND_VIA82XX config SND_VIA82XX_MODEM tristate "VIA 82C686A/B, 8233 based Modems" + depends on HAS_IOPORT select SND_AC97_CODEC help Say Y here to include support for the integrated MC97 modem on @@ -873,6 +893,7 @@ config SND_VIA82XX_MODEM config SND_VIRTUOSO tristate "Asus Virtuoso 66/100/200 (Xonar)" + depends on HAS_IOPORT select SND_OXYGEN_LIB select SND_PCM select SND_MPU401_UART @@ -889,6 +910,7 @@ config SND_VIRTUOSO config SND_VX222 tristate "Digigram VX222" + depends on HAS_IOPORT select SND_VX_LIB help Say Y here to include support for Digigram VX222 soundcards. @@ -898,6 +920,7 @@ config SND_VX222 config SND_YMFPCI tristate "Yamaha YMF724/740/744/754" + depends on HAS_IOPORT select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index b8163f26004a..23adace1b969 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -34,7 +34,6 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; static bool enable_ir[SNDRV_CARDS]; static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ -static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); @@ -56,8 +55,6 @@ module_param_array(enable_ir, bool, NULL, 0444); MODULE_PARM_DESC(enable_ir, "Enable IR."); module_param_array(subsystem, uint, NULL, 0444); MODULE_PARM_DESC(subsystem, "Force card subsystem model."); -module_param_array(delay_pcm_irq, uint, NULL, 0444); -MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0)."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ @@ -103,13 +100,14 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, enable_ir[dev], subsystem[dev]); if (err < 0) return err; - emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; err = snd_emu10k1_pcm(emu, 0); if (err < 0) return err; - err = snd_emu10k1_pcm_mic(emu, 1); - if (err < 0) - return err; + if (emu->card_capabilities->ac97_chip) { + err = snd_emu10k1_pcm_mic(emu, 1); + if (err < 0) + return err; + } err = snd_emu10k1_pcm_efx(emu, 2); if (err < 0) return err; diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 9455df18f7b2..ad0dea0c2be9 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -33,9 +33,8 @@ static void release_voice(struct snd_emux_voice *vp); static void update_voice(struct snd_emux_voice *vp, int update); static void terminate_voice(struct snd_emux_voice *vp); static void free_voice(struct snd_emux_voice *vp); -static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); -static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); -static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); +static u32 make_fmmod(struct snd_emux_voice *vp); +static u32 make_fm2frq2(struct snd_emux_voice *vp); /* * Ensure a value is between two points @@ -116,14 +115,13 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) static void release_voice(struct snd_emux_voice *vp) { - int dcysusv; struct snd_emu10k1 *hw; hw = vp->hw; - dcysusv = (unsigned char)vp->reg.parm.modrelease | DCYSUSM_PHASE1_MASK; - snd_emu10k1_ptr_write(hw, DCYSUSM, vp->ch, dcysusv); - dcysusv = (unsigned char)vp->reg.parm.volrelease | DCYSUSV_PHASE1_MASK | DCYSUSV_CHANNELENABLE_MASK; - snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, dcysusv); + snd_emu10k1_ptr_write_multiple(hw, vp->ch, + DCYSUSM, (unsigned char)vp->reg.parm.modrelease | DCYSUSM_PHASE1_MASK, + DCYSUSV, (unsigned char)vp->reg.parm.volrelease | DCYSUSV_PHASE1_MASK | DCYSUSV_CHANNELENABLE_MASK, + REGLIST_END); } @@ -138,8 +136,13 @@ terminate_voice(struct snd_emux_voice *vp) if (snd_BUG_ON(!vp)) return; hw = vp->hw; - snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, - DCYSUSV_PHASE1_MASK | DCYSUSV_DECAYTIME_MASK | DCYSUSV_CHANNELENABLE_MASK); + snd_emu10k1_ptr_write_multiple(hw, vp->ch, + DCYSUSV, 0, + VTFT, VTFT_FILTERTARGET_MASK, + CVCF, CVCF_CURRENTFILTER_MASK, + PTRX, 0, + CPF, 0, + REGLIST_END); if (vp->block) { struct snd_emu10k1_memblk *emem; emem = (struct snd_emu10k1_memblk *)vp->block; @@ -162,11 +165,6 @@ free_voice(struct snd_emux_voice *vp) /* Problem apparent on plug, unplug then plug */ /* on the Audigy 2 ZS Notebook. */ if (hw && (vp->ch >= 0)) { - snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); - snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); - // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); - snd_emu10k1_ptr_write(hw, VTFT, vp->ch, 0xffff); - snd_emu10k1_ptr_write(hw, CVCF, vp->ch, 0xffff); snd_emu10k1_voice_free(hw, &hw->voices[vp->ch]); vp->emu->num_voices--; vp->ch = -1; @@ -192,13 +190,13 @@ update_voice(struct snd_emux_voice *vp, int update) snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_B, vp->ch, vp->aaux); } if (update & SNDRV_EMUX_UPDATE_FMMOD) - set_fmmod(hw, vp); + snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, make_fmmod(vp)); if (update & SNDRV_EMUX_UPDATE_TREMFREQ) snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq); if (update & SNDRV_EMUX_UPDATE_FM2FRQ2) - set_fm2frq2(hw, vp); + snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, make_fm2frq2(vp)); if (update & SNDRV_EMUX_UPDATE_Q) - set_filterQ(hw, vp); + snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ); } @@ -255,7 +253,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, /* check if sample is finished playing (non-looping only) */ if (bp != best + V_OFF && bp != best + V_FREE && (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) { - val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch); + val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64; if (val >= vp->reg.loopstart) bp = best + V_OFF; } @@ -289,7 +287,7 @@ get_voice(struct snd_emux *emu, struct snd_emux_port *port) if (vp->ch < 0) { /* allocate a voice */ struct snd_emu10k1_voice *hwvoice; - if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, &hwvoice) < 0 || hwvoice == NULL) + if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, 1, NULL, &hwvoice) < 0) continue; vp->ch = hwvoice->number; emu->num_voices++; @@ -310,6 +308,7 @@ start_voice(struct snd_emux_voice *vp) { unsigned int temp; int ch; + u32 psst, dsl, map, ccca, vtarget; unsigned int addr, mapped_offset; struct snd_midi_channel *chan; struct snd_emu10k1 *hw; @@ -347,114 +346,98 @@ start_voice(struct snd_emux_voice *vp) snd_emu10k1_ptr_write(hw, FXRT, ch, temp); } - /* channel to be silent and idle */ - snd_emu10k1_ptr_write(hw, DCYSUSV, ch, 0); - snd_emu10k1_ptr_write(hw, VTFT, ch, VTFT_FILTERTARGET_MASK); - snd_emu10k1_ptr_write(hw, CVCF, ch, CVCF_CURRENTFILTER_MASK); - snd_emu10k1_ptr_write(hw, PTRX, ch, 0); - snd_emu10k1_ptr_write(hw, CPF, ch, 0); - - /* set pitch offset */ - snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch); - - /* set envelope parameters */ - snd_emu10k1_ptr_write(hw, ENVVAL, ch, vp->reg.parm.moddelay); - snd_emu10k1_ptr_write(hw, ATKHLDM, ch, vp->reg.parm.modatkhld); - snd_emu10k1_ptr_write(hw, DCYSUSM, ch, vp->reg.parm.moddcysus); - snd_emu10k1_ptr_write(hw, ENVVOL, ch, vp->reg.parm.voldelay); - snd_emu10k1_ptr_write(hw, ATKHLDV, ch, vp->reg.parm.volatkhld); - /* decay/sustain parameter for volume envelope is used - for triggerg the voice */ - - /* cutoff and volume */ - temp = (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol; - snd_emu10k1_ptr_write(hw, IFATN, vp->ch, temp); - - /* modulation envelope heights */ - snd_emu10k1_ptr_write(hw, PEFE, ch, vp->reg.parm.pefe); - - /* lfo1/2 delay */ - snd_emu10k1_ptr_write(hw, LFOVAL1, ch, vp->reg.parm.lfo1delay); - snd_emu10k1_ptr_write(hw, LFOVAL2, ch, vp->reg.parm.lfo2delay); - - /* lfo1 pitch & cutoff shift */ - set_fmmod(hw, vp); - /* lfo1 volume & freq */ - snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq); - /* lfo2 pitch & freq */ - set_fm2frq2(hw, vp); - - /* reverb and loop start (reverb 8bit, MSB) */ temp = vp->reg.parm.reverb; temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10; LIMITMAX(temp, 255); addr = vp->reg.loopstart; - snd_emu10k1_ptr_write(hw, PSST, vp->ch, (temp << 24) | addr); + psst = (temp << 24) | addr; - /* chorus & loop end (chorus 8bit, MSB) */ addr = vp->reg.loopend; temp = vp->reg.parm.chorus; temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10; LIMITMAX(temp, 255); - temp = (temp <<24) | addr; - snd_emu10k1_ptr_write(hw, DSL, ch, temp); + dsl = (temp << 24) | addr; - /* clear filter delay memory */ - snd_emu10k1_ptr_write(hw, Z1, ch, 0); - snd_emu10k1_ptr_write(hw, Z2, ch, 0); + map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - /* invalidate maps */ - temp = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - snd_emu10k1_ptr_write(hw, MAPA, ch, temp); - snd_emu10k1_ptr_write(hw, MAPB, ch, temp); -#if 0 - /* cache */ - { - unsigned int val, sample; - val = 32; - if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) - sample = 0x80808080; - else { - sample = 0; - val *= 2; - } - - /* cache */ - snd_emu10k1_ptr_write(hw, CCR, ch, 0x1c << 16); - snd_emu10k1_ptr_write(hw, CDE, ch, sample); - snd_emu10k1_ptr_write(hw, CDF, ch, sample); - - /* invalidate maps */ - temp = ((unsigned int)hw->silent_page.addr << hw_address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - snd_emu10k1_ptr_write(hw, MAPA, ch, temp); - snd_emu10k1_ptr_write(hw, MAPB, ch, temp); - - /* fill cache */ - val -= 4; - val <<= 25; - val |= 0x1c << 16; - snd_emu10k1_ptr_write(hw, CCR, ch, val); - } -#endif - - /* Q & current address (Q 4bit value, MSB) */ - addr = vp->reg.start; + addr = vp->reg.start + 64; temp = vp->reg.parm.filterQ; - temp = (temp<<28) | addr; + ccca = (temp << 28) | addr; if (vp->apitch < 0xe400) - temp |= CCCA_INTERPROM_0; + ccca |= CCCA_INTERPROM_0; else { unsigned int shift = (vp->apitch - 0xe000) >> 10; - temp |= shift << 25; + ccca |= shift << 25; } if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) - temp |= CCCA_8BITSELECT; - snd_emu10k1_ptr_write(hw, CCCA, ch, temp); + ccca |= CCCA_8BITSELECT; + + vtarget = (unsigned int)vp->vtarget << 16; + + snd_emu10k1_ptr_write_multiple(hw, ch, + /* channel to be silent and idle */ + DCYSUSV, 0, + VTFT, VTFT_FILTERTARGET_MASK, + CVCF, CVCF_CURRENTFILTER_MASK, + PTRX, 0, + CPF, 0, + + /* set pitch offset */ + IP, vp->apitch, + + /* set envelope parameters */ + ENVVAL, vp->reg.parm.moddelay, + ATKHLDM, vp->reg.parm.modatkhld, + DCYSUSM, vp->reg.parm.moddcysus, + ENVVOL, vp->reg.parm.voldelay, + ATKHLDV, vp->reg.parm.volatkhld, + /* decay/sustain parameter for volume envelope is used + for triggerg the voice */ + + /* cutoff and volume */ + IFATN, (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol, + + /* modulation envelope heights */ + PEFE, vp->reg.parm.pefe, + + /* lfo1/2 delay */ + LFOVAL1, vp->reg.parm.lfo1delay, + LFOVAL2, vp->reg.parm.lfo2delay, + + /* lfo1 pitch & cutoff shift */ + FMMOD, make_fmmod(vp), + /* lfo1 volume & freq */ + TREMFRQ, vp->reg.parm.tremfrq, + /* lfo2 pitch & freq */ + FM2FRQ2, make_fm2frq2(vp), - /* reset volume */ - temp = (unsigned int)vp->vtarget << 16; - snd_emu10k1_ptr_write(hw, VTFT, ch, temp | vp->ftarget); - snd_emu10k1_ptr_write(hw, CVCF, ch, temp | CVCF_CURRENTFILTER_MASK); + /* reverb and loop start (reverb 8bit, MSB) */ + PSST, psst, + + /* chorus & loop end (chorus 8bit, MSB) */ + DSL, dsl, + + /* clear filter delay memory */ + Z1, 0, + Z2, 0, + + /* invalidate maps */ + MAPA, map, + MAPB, map, + + /* Q & current address (Q 4bit value, MSB) */ + CCCA, ccca, + + /* cache */ + CCR, REG_VAL_PUT(CCR_CACHEINVALIDSIZE, 64), + + /* reset volume */ + VTFT, vtarget | vp->ftarget, + CVCF, vtarget | CVCF_CURRENTFILTER_MASK, + + REGLIST_END); + + hw->voices[ch].dirty = 1; return 0; } @@ -464,7 +447,7 @@ start_voice(struct snd_emux_voice *vp) static void trigger_voice(struct snd_emux_voice *vp) { - unsigned int temp, ptarget; + unsigned int ptarget; struct snd_emu10k1 *hw; struct snd_emu10k1_memblk *emem; @@ -479,24 +462,25 @@ trigger_voice(struct snd_emux_voice *vp) #else ptarget = IP_TO_CP(vp->apitch); #endif - /* set pitch target and pan (volume) */ - temp = ptarget | (vp->apan << 8) | vp->aaux; - snd_emu10k1_ptr_write(hw, PTRX, vp->ch, temp); + snd_emu10k1_ptr_write_multiple(hw, vp->ch, + /* set pitch target and pan (volume) */ + PTRX, ptarget | (vp->apan << 8) | vp->aaux, + + /* current pitch and fractional address */ + CPF, ptarget, - /* pitch target */ - snd_emu10k1_ptr_write(hw, CPF, vp->ch, ptarget); + /* enable envelope engine */ + DCYSUSV, vp->reg.parm.voldcysus | DCYSUSV_CHANNELENABLE_MASK, - /* trigger voice */ - snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, vp->reg.parm.voldcysus|DCYSUSV_CHANNELENABLE_MASK); + REGLIST_END); } #define MOD_SENSE 18 -/* set lfo1 modulation height and cutoff */ -static void -set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) +/* calculate lfo1 modulation height and cutoff register */ +static u32 +make_fmmod(struct snd_emux_voice *vp) { - unsigned short fmmod; short pitch; unsigned char cutoff; int modulation; @@ -506,15 +490,13 @@ set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) modulation = vp->chan->gm_modulation + vp->chan->midi_pressure; pitch += (MOD_SENSE * modulation) / 1200; LIMITVALUE(pitch, -128, 127); - fmmod = ((unsigned char)pitch<<8) | cutoff; - snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, fmmod); + return ((unsigned char)pitch << 8) | cutoff; } -/* set lfo2 pitch & frequency */ -static void -set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) +/* calculate set lfo2 pitch & frequency register */ +static u32 +make_fm2frq2(struct snd_emux_voice *vp) { - unsigned short fm2frq2; short pitch; unsigned char freq; int modulation; @@ -524,13 +506,5 @@ set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) modulation = vp->chan->gm_modulation + vp->chan->midi_pressure; pitch += (MOD_SENSE * modulation) / 1200; LIMITVALUE(pitch, -128, 127); - fm2frq2 = ((unsigned char)pitch<<8) | freq; - snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, fm2frq2); -} - -/* set filterQ */ -static void -set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) -{ - snd_emu10k1_ptr_write(hw, CCCA_RESONANCE, vp->ch, vp->reg.parm.filterQ); + return ((unsigned char)pitch << 8) | freq; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 192208c291d6..65207ef689cb 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -57,46 +57,49 @@ MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME); void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch) { - snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); - snd_emu10k1_ptr_write(emu, IP, ch, 0); - snd_emu10k1_ptr_write(emu, VTFT, ch, VTFT_FILTERTARGET_MASK); - snd_emu10k1_ptr_write(emu, CVCF, ch, CVCF_CURRENTFILTER_MASK); - snd_emu10k1_ptr_write(emu, PTRX, ch, 0); - snd_emu10k1_ptr_write(emu, CPF, ch, 0); - snd_emu10k1_ptr_write(emu, CCR, ch, 0); - - snd_emu10k1_ptr_write(emu, PSST, ch, 0); - snd_emu10k1_ptr_write(emu, DSL, ch, 0x10); - snd_emu10k1_ptr_write(emu, CCCA, ch, 0); - snd_emu10k1_ptr_write(emu, Z1, ch, 0); - snd_emu10k1_ptr_write(emu, Z2, ch, 0); - snd_emu10k1_ptr_write(emu, FXRT, ch, 0x32100000); - - snd_emu10k1_ptr_write(emu, ATKHLDM, ch, 0); - snd_emu10k1_ptr_write(emu, DCYSUSM, ch, 0); - snd_emu10k1_ptr_write(emu, IFATN, ch, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK); - snd_emu10k1_ptr_write(emu, PEFE, ch, 0); - snd_emu10k1_ptr_write(emu, FMMOD, ch, 0); - snd_emu10k1_ptr_write(emu, TREMFRQ, ch, 24); /* 1 Hz */ - snd_emu10k1_ptr_write(emu, FM2FRQ2, ch, 24); /* 1 Hz */ - snd_emu10k1_ptr_write(emu, TEMPENV, ch, 0); - - /*** these are last so OFF prevents writing ***/ - snd_emu10k1_ptr_write(emu, LFOVAL2, ch, 0); - snd_emu10k1_ptr_write(emu, LFOVAL1, ch, 0); - snd_emu10k1_ptr_write(emu, ATKHLDV, ch, 0); - snd_emu10k1_ptr_write(emu, ENVVOL, ch, 0); - snd_emu10k1_ptr_write(emu, ENVVAL, ch, 0); + snd_emu10k1_ptr_write_multiple(emu, ch, + DCYSUSV, 0, + VTFT, VTFT_FILTERTARGET_MASK, + CVCF, CVCF_CURRENTFILTER_MASK, + PTRX, 0, + CPF, 0, + CCR, 0, + + PSST, 0, + DSL, 0x10, + CCCA, 0, + Z1, 0, + Z2, 0, + FXRT, 0x32100000, + + // The rest is meaningless as long as DCYSUSV_CHANNELENABLE_MASK is zero + DCYSUSM, 0, + ATKHLDV, 0, + ATKHLDM, 0, + IP, 0, + IFATN, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK, + PEFE, 0, + FMMOD, 0, + TREMFRQ, 24, /* 1 Hz */ + FM2FRQ2, 24, /* 1 Hz */ + LFOVAL2, 0, + LFOVAL1, 0, + ENVVOL, 0, + ENVVAL, 0, + + REGLIST_END); /* Audigy extra stuffs */ if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_CSBA, ch, 0); - snd_emu10k1_ptr_write(emu, A_CSDC, ch, 0); - snd_emu10k1_ptr_write(emu, A_CSFE, ch, 0); - snd_emu10k1_ptr_write(emu, A_CSHG, ch, 0); - snd_emu10k1_ptr_write(emu, A_FXRT1, ch, 0x03020100); - snd_emu10k1_ptr_write(emu, A_FXRT2, ch, 0x3f3f3f3f); - snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, ch, 0); + snd_emu10k1_ptr_write_multiple(emu, ch, + A_CSBA, 0, + A_CSDC, 0, + A_CSFE, 0, + A_CSHG, 0, + A_FXRT1, 0x03020100, + A_FXRT2, 0x07060504, + A_SENDAMOUNTS, 0, + REGLIST_END); } } @@ -150,22 +153,26 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir) outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); - /* reset recording buffers */ - snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); - snd_emu10k1_ptr_write(emu, MICBA, 0, 0); - snd_emu10k1_ptr_write(emu, FXBS, 0, ADCBS_BUFSIZE_NONE); - snd_emu10k1_ptr_write(emu, FXBA, 0, 0); - snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); - snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); - - /* disable channel interrupt */ outl(0, emu->port + INTE); - snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); - snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); - /* disable stop on loop end */ - snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); - snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); + snd_emu10k1_ptr_write_multiple(emu, 0, + /* reset recording buffers */ + MICBS, ADCBS_BUFSIZE_NONE, + MICBA, 0, + FXBS, ADCBS_BUFSIZE_NONE, + FXBA, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + + /* disable channel interrupt */ + CLIEL, 0, + CLIEH, 0, + + /* disable stop on loop end */ + SOLEL, 0, + SOLEH, 0, + + REGLIST_END); if (emu->audigy) { /* set SPDIF bypass mode */ @@ -179,9 +186,11 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir) for (ch = 0; ch < NUM_G; ch++) snd_emu10k1_voice_init(emu, ch); - snd_emu10k1_ptr_write(emu, SPCS0, 0, emu->spdif_bits[0]); - snd_emu10k1_ptr_write(emu, SPCS1, 0, emu->spdif_bits[1]); - snd_emu10k1_ptr_write(emu, SPCS2, 0, emu->spdif_bits[2]); + snd_emu10k1_ptr_write_multiple(emu, 0, + SPCS0, emu->spdif_bits[0], + SPCS1, emu->spdif_bits[1], + SPCS2, emu->spdif_bits[2], + REGLIST_END); if (emu->card_capabilities->emu_model) { } else if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ @@ -392,41 +401,48 @@ int snd_emu10k1_done(struct snd_emu10k1 *emu) outl(0, emu->port + INTE); /* - * Shutdown the chip + * Shutdown the voices */ - for (ch = 0; ch < NUM_G; ch++) - snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); for (ch = 0; ch < NUM_G; ch++) { - snd_emu10k1_ptr_write(emu, VTFT, ch, 0); - snd_emu10k1_ptr_write(emu, CVCF, ch, 0); - snd_emu10k1_ptr_write(emu, PTRX, ch, 0); - snd_emu10k1_ptr_write(emu, CPF, ch, 0); + snd_emu10k1_ptr_write_multiple(emu, ch, + DCYSUSV, 0, + VTFT, 0, + CVCF, 0, + PTRX, 0, + CPF, 0, + REGLIST_END); } - /* reset recording buffers */ - snd_emu10k1_ptr_write(emu, MICBS, 0, 0); - snd_emu10k1_ptr_write(emu, MICBA, 0, 0); - snd_emu10k1_ptr_write(emu, FXBS, 0, 0); - snd_emu10k1_ptr_write(emu, FXBA, 0, 0); - snd_emu10k1_ptr_write(emu, FXWC, 0, 0); - snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); - snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); - snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); - snd_emu10k1_ptr_write(emu, TCB, 0, 0); + // stop the DSP if (emu->audigy) snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, EMU10K1_DBG_SINGLE_STEP); - /* disable channel interrupt */ - snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); - snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); - snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); - snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); + snd_emu10k1_ptr_write_multiple(emu, 0, + /* reset recording buffers */ + MICBS, 0, + MICBA, 0, + FXBS, 0, + FXBA, 0, + FXWC, 0, + ADCBS, ADCBS_BUFSIZE_NONE, + ADCBA, 0, + TCBS, TCBS_BUFFSIZE_16K, + TCB, 0, + + /* disable channel interrupt */ + CLIEL, 0, + CLIEH, 0, + SOLEL, 0, + SOLEH, 0, + + PTB, 0, + + REGLIST_END); /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); - snd_emu10k1_ptr_write(emu, PTB, 0, 0); return 0; } @@ -798,7 +814,6 @@ static void emu1010_firmware_work(struct work_struct *work) */ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) { - unsigned int i; u32 tmp, tmp2, reg; int err; @@ -855,9 +870,14 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); - /* Optical -> ADAT I/O */ - emu->emu1010.optical_in = 1; /* IN_ADAT */ - emu->emu1010.optical_out = 1; /* OUT_ADAT */ + if (emu->card_capabilities->no_adat) { + emu->emu1010.optical_in = 0; /* IN_SPDIF */ + emu->emu1010.optical_out = 0; /* OUT_SPDIF */ + } else { + /* Optical -> ADAT I/O */ + emu->emu1010.optical_in = 1; /* IN_ADAT */ + emu->emu1010.optical_out = 1; /* OUT_ADAT */ + } tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) | (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF); snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); @@ -889,253 +909,10 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* Audio Dock LEDs. */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_LOCK | EMU_HANA_DOCK_LEDS_2_48K); -#if 0 - /* For 96kHz */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT2); -#endif -#if 0 - /* For 192kHz */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_0, EMU_SRC_HAMOA_ADC_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_1, EMU_SRC_HAMOA_ADC_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_RIGHT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_4, EMU_SRC_HAMOA_ADC_LEFT3); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_5, EMU_SRC_HAMOA_ADC_RIGHT3); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_6, EMU_SRC_HAMOA_ADC_LEFT4); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_7, EMU_SRC_HAMOA_ADC_RIGHT4); -#endif -#if 1 - /* For 48kHz */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_0, EMU_SRC_DOCK_MIC_A1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_1, EMU_SRC_DOCK_MIC_B1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_2, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_3, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_4, EMU_SRC_DOCK_ADC1_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_5, EMU_SRC_DOCK_ADC1_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1); - /* Pavel Hofman - setting defaults for 8 more capture channels - * Defaults only, users will set their own values anyways, let's - * just copy/paste. - */ - - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1); -#endif -#if 0 - /* Original */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_4, EMU_SRC_HANA_ADAT); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_5, EMU_SRC_HANA_ADAT + 1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_6, EMU_SRC_HANA_ADAT + 2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_7, EMU_SRC_HANA_ADAT + 3); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_8, EMU_SRC_HANA_ADAT + 4); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_9, EMU_SRC_HANA_ADAT + 5); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_A, EMU_SRC_HANA_ADAT + 6); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_B, EMU_SRC_HANA_ADAT + 7); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_MIC_A1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_MIC_B1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_E, EMU_SRC_HAMOA_ADC_LEFT2); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE2_EMU32_F, EMU_SRC_HAMOA_ADC_LEFT2); -#endif - for (i = 0; i < 0x20; i++) { - /* AudioDock Elink <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0100 + i, EMU_SRC_SILENCE); - } - for (i = 0; i < 4; i++) { - /* Hana SPDIF Out <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0200 + i, EMU_SRC_SILENCE); - } - for (i = 0; i < 7; i++) { - /* Hamoa DAC <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, 0x0300 + i, EMU_SRC_SILENCE); - } - for (i = 0; i < 7; i++) { - /* Hana ADAT Out <- Silence */ - snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HANA_ADAT + i, EMU_SRC_SILENCE); - } - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S0_LEFT, EMU_SRC_DOCK_ADC1_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S0_RIGHT, EMU_SRC_DOCK_ADC1_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S1_LEFT, EMU_SRC_DOCK_ADC2_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S1_RIGHT, EMU_SRC_DOCK_ADC2_RIGHT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S2_LEFT, EMU_SRC_DOCK_ADC3_LEFT1); - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_ALICE_I2S2_RIGHT, EMU_SRC_DOCK_ADC3_RIGHT1); + // The routes are all set to EMU_SRC_SILENCE due to the reset, + // so it is safe to simply enable the outputs. snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); -#if 0 - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32B + 3); /* ALICE2 bus 0xa3 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 2); /* ALICE2 bus 0xb2 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); /* ALICE2 bus 0xb3 */ -#endif - /* Default outputs */ - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - /* 1616(M) cardbus default outputs */ - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[0] = 17; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[1] = 18; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); - emu->emu1010.output_source[2] = 19; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); - emu->emu1010.output_source[3] = 20; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); - emu->emu1010.output_source[4] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); - emu->emu1010.output_source[5] = 22; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_MANA_DAC_LEFT, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[16] = 17; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_MANA_DAC_RIGHT, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[17] = 18; - } else { - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC1_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[0] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC1_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[1] = 22; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC2_LEFT1, EMU_SRC_ALICE_EMU32A + 2); - emu->emu1010.output_source[2] = 23; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC2_RIGHT1, EMU_SRC_ALICE_EMU32A + 3); - emu->emu1010.output_source[3] = 24; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC3_LEFT1, EMU_SRC_ALICE_EMU32A + 4); - emu->emu1010.output_source[4] = 25; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC3_RIGHT1, EMU_SRC_ALICE_EMU32A + 5); - emu->emu1010.output_source[5] = 26; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC4_LEFT1, EMU_SRC_ALICE_EMU32A + 6); - emu->emu1010.output_source[6] = 27; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_DAC4_RIGHT1, EMU_SRC_ALICE_EMU32A + 7); - emu->emu1010.output_source[7] = 28; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_PHONES_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[8] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_PHONES_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[9] = 22; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[10] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_DOCK_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[11] = 22; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_SPDIF_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[12] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_SPDIF_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[13] = 22; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[14] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HAMOA_DAC_RIGHT1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[15] = 22; - /* ALICE2 bus 0xa0 */ - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT, EMU_SRC_ALICE_EMU32A + 0); - emu->emu1010.output_source[16] = 21; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 1, EMU_SRC_ALICE_EMU32A + 1); - emu->emu1010.output_source[17] = 22; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 2, EMU_SRC_ALICE_EMU32A + 2); - emu->emu1010.output_source[18] = 23; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 3, EMU_SRC_ALICE_EMU32A + 3); - emu->emu1010.output_source[19] = 24; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 4, EMU_SRC_ALICE_EMU32A + 4); - emu->emu1010.output_source[20] = 25; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 5, EMU_SRC_ALICE_EMU32A + 5); - emu->emu1010.output_source[21] = 26; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 6, EMU_SRC_ALICE_EMU32A + 6); - emu->emu1010.output_source[22] = 27; - snd_emu1010_fpga_link_dst_src_write(emu, - EMU_DST_HANA_ADAT + 7, EMU_SRC_ALICE_EMU32A + 7); - emu->emu1010.output_source[23] = 28; - } - return 0; } /* @@ -1310,7 +1087,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { /* Does NOT support sync daughter card (obviously). */ /* Tested by [email protected] 4th Nov 2007. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102, - .driver = "Audigy2", .name = "E-mu 1010 Notebook [MAEM8950]", + .driver = "Audigy2", .name = "E-MU 02 CardBus [MAEM8950]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1323,7 +1100,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { * MicroDock[M] to make it an E-MU 1616[m]. */ /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102, - .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM8960]", + .driver = "Audigy2", .name = "E-MU 1010b PCI [MAEM8960]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1337,7 +1114,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { * still work. */ /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102, - .driver = "Audigy2", .name = "E-mu 1010 PCIe [MAEM8986]", + .driver = "Audigy2", .name = "E-MU 1010 PCIe [MAEM8986]", .id = "EMU1010", .emu10k2_chip = 1, .ca0108_chip = 1, @@ -1349,7 +1126,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { * AudioDock[M] to make it an E-MU 1820[m]. */ /* Supports sync daughter card. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102, - .driver = "Audigy2", .name = "E-mu 1010 [MAEM8810]", + .driver = "Audigy2", .name = "E-MU 1010 [MAEM8810]", .id = "EMU1010", .emu10k2_chip = 1, .ca0102_chip = 1, @@ -1359,30 +1136,33 @@ static const struct snd_emu_chip_details emu_chip_details[] = { /* Supports sync daughter card. */ /* Tested by [email protected] Mar 2023. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404b PCI [MAEM8852]", + .driver = "Audigy2", .name = "E-MU 0404b PCI [MAEM8852]", .id = "EMU0404", .emu10k2_chip = 1, .ca0108_chip = 1, - .spk71 = 1, + .spk20 = 1, + .no_adat = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */ /* This is MAEM8850 "HanaLite" */ /* Supports sync daughter card. */ /* Tested by [email protected] 20-3-2007. */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102, - .driver = "Audigy2", .name = "E-mu 0404 [MAEM8850]", + .driver = "Audigy2", .name = "E-MU 0404 [MAEM8850]", .id = "EMU0404", .emu10k2_chip = 1, .ca0102_chip = 1, - .spk71 = 1, + .spk20 = 1, + .no_adat = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */ /* EMU0404 PCIe */ /* Does NOT support sync daughter card. */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102, - .driver = "Audigy2", .name = "E-mu 0404 PCIe [MAEM8984]", + .driver = "Audigy2", .name = "E-MU 0404 PCIe [MAEM8984]", .id = "EMU0404", .emu10k2_chip = 1, .ca0108_chip = 1, - .spk71 = 1, + .spk20 = 1, + .no_adat = 1, .emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 PCIe ver_03 */ {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", @@ -1645,7 +1425,7 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, - .driver = "EMU10K1", .name = "E-mu APS [PC545]", + .driver = "EMU10K1", .name = "E-MU APS [PC545]", .id = "APS", .emu10k1_chip = 1, .ecard = 1} , diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 3f64ccab0e63..e9855d37fa5c 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -318,16 +318,12 @@ static int snd_emu10k1_gpr_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_emu10k1_gpr_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_fx8010_ctl *ctl = (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value; - unsigned long flags; unsigned int i; - spin_lock_irqsave(&emu->reg_lock, flags); for (i = 0; i < ctl->vcount; i++) ucontrol->value.integer.value[i] = ctl->value[i]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -336,12 +332,10 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_fx8010_ctl *ctl = (struct snd_emu10k1_fx8010_ctl *) kcontrol->private_value; - unsigned long flags; - unsigned int nval, val; + int nval, val; unsigned int i, j; int change = 0; - spin_lock_irqsave(&emu->reg_lock, flags); for (i = 0; i < ctl->vcount; i++) { nval = ucontrol->value.integer.value[i]; if (nval < ctl->min) @@ -355,9 +349,16 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl case EMU10K1_GPR_TRANSLATION_NONE: snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val); break; + case EMU10K1_GPR_TRANSLATION_NEGATE: + snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, ~val); + break; case EMU10K1_GPR_TRANSLATION_TABLE100: snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]); break; + case EMU10K1_GPR_TRANSLATION_NEG_TABLE100: + snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, + val == 100 ? 0x80000000 : -(int)db_table[val]); + break; case EMU10K1_GPR_TRANSLATION_BASS: if ((ctl->count % 5) != 0 || (ctl->count / 5) != ctl->vcount) { change = -EIO; @@ -380,7 +381,6 @@ static int snd_emu10k1_gpr_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl } } __error: - spin_unlock_irqrestore(&emu->reg_lock, flags); return change; } @@ -776,6 +776,34 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, err = -EINVAL; goto __error; } + switch (gctl->translation) { + case EMU10K1_GPR_TRANSLATION_NONE: + case EMU10K1_GPR_TRANSLATION_NEGATE: + break; + case EMU10K1_GPR_TRANSLATION_TABLE100: + case EMU10K1_GPR_TRANSLATION_NEG_TABLE100: + if (gctl->min != 0 || gctl->max != 100) { + err = -EINVAL; + goto __error; + } + break; + case EMU10K1_GPR_TRANSLATION_BASS: + case EMU10K1_GPR_TRANSLATION_TREBLE: + if (gctl->min != 0 || gctl->max != 40) { + err = -EINVAL; + goto __error; + } + break; + case EMU10K1_GPR_TRANSLATION_ONOFF: + if (gctl->min != 0 || gctl->max != 1) { + err = -EINVAL; + goto __error; + } + break; + default: + err = -EINVAL; + goto __error; + } } for (i = 0; i < icode->gpr_list_control_count; i++) { /* FIXME: we need to check the WRITE access */ @@ -1116,48 +1144,56 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, #define SND_EMU10K1_PLAYBACK_CHANNELS 8 #define SND_EMU10K1_CAPTURE_CHANNELS 4 +#define HR_VAL(v) ((v) * 0x80000000LL / 100 - 1) + static void -snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval) +snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, + const char *name, int gpr, int defval, int defval_hr) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 1; - ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; if (high_res_gpr_volume) { - ctl->min = 0; + ctl->min = -1; ctl->max = 0x7fffffff; ctl->tlv = snd_emu10k1_db_linear; - ctl->translation = EMU10K1_GPR_TRANSLATION_NONE; + ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE; + defval = defval_hr; } else { ctl->min = 0; ctl->max = 100; ctl->tlv = snd_emu10k1_db_scale1; - ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; + ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100; } + ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; } +#define snd_emu10k1_init_mono_control(ctl, name, gpr, defval) \ + snd_emu10k1_init_mono_control2(ctl, name, gpr, defval, HR_VAL(defval)) static void -snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, - const char *name, int gpr, int defval) +snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl, + const char *name, int gpr, int defval, int defval_hr) { ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 2; - ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; - ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; if (high_res_gpr_volume) { - ctl->min = 0; + ctl->min = -1; ctl->max = 0x7fffffff; ctl->tlv = snd_emu10k1_db_linear; - ctl->translation = EMU10K1_GPR_TRANSLATION_NONE; + ctl->translation = EMU10K1_GPR_TRANSLATION_NEGATE; + defval = defval_hr; } else { ctl->min = 0; ctl->max = 100; ctl->tlv = snd_emu10k1_db_scale1; - ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; + ctl->translation = EMU10K1_GPR_TRANSLATION_NEG_TABLE100; } + ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; + ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; } +#define snd_emu10k1_init_stereo_control(ctl, name, gpr, defval) \ + snd_emu10k1_init_stereo_control2(ctl, name, gpr, defval, HR_VAL(defval)) static void snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, @@ -1191,35 +1227,50 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl * to 2 x 16-bit registers in Audigy - their values are read via DMA. * Conversion is performed by Audigy DSP instructions of FX8010. */ -static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( +static void 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) { - A_OP(icode, ptr, iACC3, A_GPR(tmp + 1), reg_in, A_C_00000000, A_C_00000000); - A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp + 1), A_GPR(bit_shifter16 - 1), A_C_00000000); - A_OP(icode, ptr, iTSTNEG, A_GPR(tmp + 2), A_GPR(tmp), A_C_80000000, A_GPR(bit_shifter16 - 2)); - A_OP(icode, ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_C_80000000, A_C_00000000); - A_OP(icode, ptr, iANDXOR, A_GPR(tmp), A_GPR(tmp), A_GPR(bit_shifter16 - 3), A_C_00000000); - A_OP(icode, ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A_GPR(tmp), A_C_00010000); - A_OP(icode, ptr, iANDXOR, reg_out, A_GPR(tmp), A_C_ffffffff, A_GPR(tmp + 2)); - A_OP(icode, ptr, iACC3, reg_out + 1, A_GPR(tmp + 1), A_C_00000000, A_C_00000000); - return 1; + // This leaves the low word in place, which is fine, + // as the low bits are completely ignored subsequently. + // reg_out[1] = reg_in + A_OP(icode, ptr, iACC3, reg_out + 1, reg_in, A_C_00000000, A_C_00000000); + // It is fine to read reg_in multiple times. + // tmp = reg_in << 15 + A_OP(icode, ptr, iMACINT1, A_GPR(tmp), A_C_00000000, reg_in, A_GPR(bit_shifter16)); + // Left-shift once more. This is a separate step, as the + // signed multiplication would clobber the MSB. + // reg_out[0] = tmp + ((tmp << 31) >> 31) + A_OP(icode, ptr, iMAC3, reg_out, A_GPR(tmp), A_GPR(tmp), A_C_80000000); } +#define ENUM_GPR(name, size) name, name ## _dummy = name + (size) - 1 + /* * initial DSP configuration for Audigy */ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { - int err, z, gpr, nctl; - int bit_shifter16; - const int playback = 10; - const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ - const int stereo_mix = capture + 2; - const int tmp = 0x88; - u32 ptr; + int err, z, nctl; + enum { + ENUM_GPR(playback, SND_EMU10K1_PLAYBACK_CHANNELS), + ENUM_GPR(stereo_mix, 2), + ENUM_GPR(capture, 2), + ENUM_GPR(bit_shifter16, 1), + // The fixed allocation of these breaks the pattern, but why not. + // Splitting these into left/right is questionable, as it will break + // down for center/lfe. But it works for stereo/quadro, so whatever. + ENUM_GPR(bass_gpr, 2 * 5), // two sides, five coefficients + ENUM_GPR(treble_gpr, 2 * 5), + ENUM_GPR(bass_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4), // four delay stages + ENUM_GPR(treble_tmp, SND_EMU10K1_PLAYBACK_CHANNELS * 4), + ENUM_GPR(tmp, 3), + num_static_gprs + }; + int gpr = num_static_gprs; + u32 ptr, ptr_skip; struct snd_emu10k1_fx8010_code *icode = NULL; struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl; u32 *gpr_map; @@ -1253,44 +1304,40 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) strcpy(icode->name, "Audigy DSP code for ALSA"); ptr = 0; nctl = 0; - gpr = stereo_mix + 10; - gpr_map[gpr++] = 0x00007fff; - gpr_map[gpr++] = 0x00008000; - gpr_map[gpr++] = 0x0000ffff; - bit_shifter16 = gpr; + gpr_map[bit_shifter16] = 0x00008000; #if 1 /* PCM front Playback Volume (independent from stereo mix) - * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31) - * where gpr contains attenuation from corresponding mixer control + * playback = -gpr * FXBUS_PCM_LEFT_FRONT >> 31 + * where gpr contains negated attenuation from corresponding mixer control * (snd_emu10k1_init_stereo_control) */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; /* PCM Surround Playback (independent from stereo mix) */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100); gpr += 2; /* PCM Side Playback (independent from stereo mix) */ if (emu->card_capabilities->spk71) { - A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); gpr += 2; } /* PCM Center Playback (independent from stereo mix) */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100); gpr++; /* PCM LFE Playback (independent from stereo mix) */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100); gpr++; @@ -1298,160 +1345,174 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) * Stereo Mix */ /* Wave (PCM) Playback Volume (will be renamed later) */ - A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); gpr += 2; /* Synth Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); + A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); + A_OP(icode, &ptr, iMAC1, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100); gpr += 2; /* Wave (PCM) Capture */ - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0); gpr += 2; /* Synth Capture */ - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); + A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); + A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); gpr += 2; - + + // We need to double the volume, as we configure the voices for half volume, + // which is necessary for bit-identical reproduction. + { static_assert(stereo_mix == playback + SND_EMU10K1_PLAYBACK_CHANNELS); } + for (z = 0; z < SND_EMU10K1_PLAYBACK_CHANNELS + 2; z++) + A_OP(icode, &ptr, iACC3, A_GPR(playback + z), A_GPR(playback + z), A_GPR(playback + z), A_C_00000000); + /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ -A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) + A_OP(icode, &ptr, iMAC1, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) if (emu->card_capabilities->emu_model) { /* EMU1010 DSP 0 and DSP 1 Capture */ // The 24 MSB hold the actual value. We implicitly discard the 16 LSB. if (emu->card_capabilities->ca0108_chip) { - /* Note:JCD:No longer bit shift lower 16bits to upper 16bits of 32bit value. */ - A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x0), A_C_00000001); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_GPR(tmp)); - A_OP(icode, &ptr, iMACINT0, A_GPR(tmp), A_C_00000000, A3_EMU32IN(0x1), A_C_00000001); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr), A_GPR(tmp)); + // For unclear reasons, the EMU32IN cannot be the Y operand! + A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A3_EMU32IN(0x0), A_GPR(gpr)); + // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels + // need to be delayed as well; we use an auxiliary register for that. + A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A3_EMU32IN(0x1), A_C_00000000, A_C_00000000); } else { - A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_P16VIN(0x0)); - A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_P16VIN(0x1)); + A_OP(icode, &ptr, iMAC1, A_GPR(capture+0), A_GPR(capture+0), A_P16VIN(0x0), A_GPR(gpr)); + // A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels + // need to be delayed as well; we use an auxiliary register for that. + A_OP(icode, &ptr, iMAC1, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+2), A_GPR(gpr+1)); + A_OP(icode, &ptr, iACC3, A_GPR(gpr+2), A_P16VIN(0x1), A_C_00000000, A_C_00000000); } snd_emu10k1_init_stereo_control(&controls[nctl++], "EMU Capture Volume", gpr, 0); - gpr += 2; - } - /* AC'97 Playback Volume - used only for mic (renamed later) */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0); - gpr += 2; - /* AC'97 Capture Volume - used only for mic */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0); - gpr += 2; + gpr_map[gpr + 2] = 0x00000000; + gpr += 3; + } else { + if (emu->card_capabilities->ac97_chip) { + /* AC'97 Playback Volume - used only for mic (renamed later) */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0); + gpr += 2; + /* AC'97 Capture Volume - used only for mic */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0); + gpr += 2; + + /* mic capture buffer */ + 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)); + } - /* mic capture buffer */ - 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)); + /* Audigy CD Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume", + gpr, 0); + gpr += 2; + /* Audigy CD Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume", + gpr, 0); + gpr += 2; - /* Audigy CD Playback Volume */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Audigy CD Playback Volume" : "CD Playback Volume", - gpr, 0); - gpr += 2; - /* Audigy CD Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Audigy CD Capture Volume" : "CD Capture Volume", - gpr, 0); - gpr += 2; + /* Optical SPDIF Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0); + gpr += 2; + /* Optical SPDIF Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0); + gpr += 2; - /* Optical SPDIF Playback Volume */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0); - gpr += 2; - /* Optical SPDIF Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0); - gpr += 2; + /* Line2 Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume", + gpr, 0); + gpr += 2; + /* Line2 Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume", + gpr, 0); + gpr += 2; - /* Line2 Playback Volume */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Line2 Playback Volume" : "Line Playback Volume", - gpr, 0); - gpr += 2; - /* Line2 Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Line2 Capture Volume" : "Line Capture Volume", - gpr, 0); - gpr += 2; - - /* Philips ADC Playback Volume */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0); - gpr += 2; - /* Philips ADC Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0); - gpr += 2; + /* Philips ADC Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0); + gpr += 2; + /* Philips ADC Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0); + gpr += 2; - /* Aux2 Playback Volume */ - A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); - A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume", - gpr, 0); - gpr += 2; - /* Aux2 Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], - emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume", - gpr, 0); - gpr += 2; + /* Aux2 Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Aux2 Playback Volume" : "Aux Playback Volume", + gpr, 0); + gpr += 2; + /* Aux2 Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], + emu->card_capabilities->ac97_chip ? "Aux2 Capture Volume" : "Aux Capture Volume", + gpr, 0); + gpr += 2; + } /* Stereo Mix Front Playback Volume */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100); gpr += 2; /* Stereo Mix Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0); gpr += 2; /* Stereo Mix Center Playback */ /* Center = sub = Left/2 + Right/2 */ A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp)); snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0); gpr++; /* Stereo Mix LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); gpr++; if (emu->card_capabilities->spk71) { /* Stereo Mix Side Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC1, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0); gpr += 2; } @@ -1476,18 +1537,6 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* * Process tone control */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ - if (emu->card_capabilities->spk71) { - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */ - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */ - } - - ctl = &controls[nctl + 0]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, "Tone Control - Bass"); @@ -1506,36 +1555,39 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) ctl->max = 40; ctl->value[0] = ctl->value[1] = 20; ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE; - -#define BASS_GPR 0x8c -#define TREBLE_GPR 0x96 - for (z = 0; z < 5; z++) { int j; for (j = 0; j < 2; j++) { - controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j; - controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j; + controls[nctl + 0].gpr[z * 2 + j] = bass_gpr + z * 2 + j; + controls[nctl + 1].gpr[z * 2 + j] = treble_gpr + z * 2 + j; } } + nctl += 2; + + A_OP(icode, &ptr, iACC3, A_C_00000000, A_GPR(gpr), A_C_00000000, A_C_00000000); + snd_emu10k1_init_mono_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); + gpr++; + A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_CC_REG_ZERO, A_GPR(gpr)); + ptr_skip = ptr; for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */ int j, k, l, d; for (j = 0; j < 2; j++) { /* left/right */ - k = 0xb0 + (z * 8) + (j * 4); - l = 0xe0 + (z * 8) + (j * 4); - d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j; - - A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j)); - A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j)); + k = bass_tmp + (z * 8) + (j * 4); + l = treble_tmp + (z * 8) + (j * 4); + d = playback + z * 2 + j; + + A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(bass_gpr + 0 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(bass_gpr + 4 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(bass_gpr + 2 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(bass_gpr + 8 + j)); + A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(bass_gpr + 6 + j)); A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000); - A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j)); - A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j)); - A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j)); + A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(treble_gpr + 0 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(treble_gpr + 4 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(treble_gpr + 2 + j)); + A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(treble_gpr + 8 + j)); + A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(treble_gpr + 6 + j)); A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010); A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000); @@ -1544,90 +1596,70 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) break; } } - nctl += 2; - -#undef BASS_GPR -#undef TREBLE_GPR - - for (z = 0; z < 8; z++) { - A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0); - A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0); - A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); - A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); - } - snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); - gpr += 2; + gpr_map[gpr++] = ptr - ptr_skip; /* Master volume (will be renamed later) */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS)); + for (z = 0; z < 8; z++) + A_OP(icode, &ptr, iMAC1, A_GPR(playback+z), A_C_00000000, A_GPR(gpr), A_GPR(playback+z)); snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); - gpr += 2; - - /* analog speakers */ - A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); - A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); - A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); - A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); - if (emu->card_capabilities->spk71) - A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); - - /* headphone */ - A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); + gpr++; - /* digital outputs */ - /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ if (emu->card_capabilities->emu_model) { /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ dev_info(emu->card->dev, "EMU outputs on\n"); for (z = 0; z < 8; z++) { if (emu->card_capabilities->ca0108_chip) { - A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + z), A_C_00000000, A_C_00000000); } else { - A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); + A_OP(icode, &ptr, iACC3, A_EMU32OUTL(z), A_GPR(playback + z), A_C_00000000, A_C_00000000); } } - } + } else { + /* analog speakers */ + A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback); + A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2); + A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4); + A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5); + if (emu->card_capabilities->spk71) + A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6); - /* IEC958 Optical Raw Playback Switch */ - gpr_map[gpr++] = 0; - gpr_map[gpr++] = 0x1008; - gpr_map[gpr++] = 0xffff0000; - for (z = 0; z < 2; z++) { - A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000); - A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001); - A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2)); - A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000); - A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z); - A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z); - A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); - if ((z==1) && (emu->card_capabilities->spdif_bug)) { - /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */ - dev_info(emu->card->dev, - "Installing spdif_bug patch: %s\n", - emu->card_capabilities->name); - A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); - } else { - A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); + /* headphone */ + A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback); + + /* IEC958 Optical Raw Playback Switch */ + gpr_map[gpr++] = 0; + gpr_map[gpr++] = 0x1008; + gpr_map[gpr++] = 0xffff0000; + for (z = 0; z < 2; z++) { + A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000); + A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001); + A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2)); + A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000); + A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z); + A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z); + A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); + if ((z==1) && (emu->card_capabilities->spdif_bug)) { + /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */ + dev_info(emu->card->dev, + "Installing spdif_bug patch: %s\n", + emu->card_capabilities->name); + A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000); + A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); + } else { + A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); + } } + snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0); + gpr += 2; + + A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2); + A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4); + A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5); } - snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0); - gpr += 2; - - A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); - A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); - A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); /* ADC buffer */ #ifdef EMU10K1_CAPTURE_DIGITAL_OUT - A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); + A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback); #else A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture); A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); @@ -1639,11 +1671,17 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) dev_info(emu->card->dev, "EMU2 inputs on\n"); /* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */ - for (z = 0; z < 0x10; z++) { + snd_emu10k1_audigy_dsp_convert_32_to_2x16( + icode, &ptr, tmp, bit_shifter16, A3_EMU32IN(0), A_FXBUS2(0)); + // A3_EMU32IN(0) is delayed by one sample, so all other A3_EMU32IN channels + // need to be delayed as well; we use an auxiliary register for that. + for (z = 1; z < 0x10; z++) { snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, - A3_EMU32IN(z), + A_GPR(gpr), A_FXBUS2(z*2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr), A3_EMU32IN(z), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; } } else { dev_info(emu->card->dev, "EMU inputs on\n"); @@ -1653,102 +1691,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n", gpr, tmp); */ - /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ - /* A_P16VIN(0) is delayed by one sample, - * so all other A_P16VIN channels will need to also be delayed - */ - /* Left ADC in. 1 of 2 */ snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) ); - /* Right ADC in 1 of 2 */ - gpr_map[gpr++] = 0x00000000; - /* Delaying by one sample: instead of copying the input - * value A_P16VIN to output A_FXBUS2 as in the first channel, - * we use an auxiliary register, delaying the value by one - * sample - */ - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(4) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x2), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(6) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x3), A_C_00000000, A_C_00000000); - /* For 96kHz mode */ - /* Left ADC in. 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0x8) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x4), A_C_00000000, A_C_00000000); - /* Right ADC in 2 of 2 */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xa) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x5), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xc) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x6), A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) ); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000); - /* Pavel Hofman - we still have voices, A_FXBUS2s, and - * A_P16VINs available - - * let's add 8 more capture channels - total of 16 - */ - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x10)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x12)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x14)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x16)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x18)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1a)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1c)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe), - A_C_00000000, A_C_00000000); - gpr_map[gpr++] = 0x00000000; - snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp, - bit_shifter16, - A_GPR(gpr - 1), - A_FXBUS2(0x1e)); - A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf), - A_C_00000000, A_C_00000000); + /* A_P16VIN(0) is delayed by one sample, so all other A_P16VIN channels + * will need to also be delayed; we use an auxiliary register for that. */ + for (z = 1; z < 0x10; z++) { + snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr), A_FXBUS2(z * 2) ); + A_OP(icode, &ptr, iACC3, A_GPR(gpr), A_P16VIN(z), A_C_00000000, A_C_00000000); + gpr_map[gpr++] = 0x00000000; + } } #if 0 @@ -1772,11 +1722,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) * ok, set up done.. */ - if (gpr > tmp) { + if (gpr > 512) { snd_BUG(); err = -EIO; goto __err; } + /* clear remaining instruction memory */ while (ptr < 0x400) A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0); @@ -1801,30 +1752,14 @@ __err_gpr: * initial DSP configuration for Emu10k1 */ -/* when volume = max, then copy only to avoid volume modification */ -/* with iMAC0 (negative values) */ +/* Volumes are in the [-2^31, 0] range, zero being mute. */ static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { - OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); - OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); - OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001); - OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); + OP(icode, ptr, iMAC1, dst, C_00000000, src, vol); } static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { - OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); - OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); - OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001); - OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); - OP(icode, ptr, iMAC0, dst, dst, src, vol); -} -static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) -{ - OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); - OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); - OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); - OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); - OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); + OP(icode, ptr, iMAC1, dst, dst, src, vol); } #define VOLUME(icode, ptr, dst, src, vol) \ @@ -1836,7 +1771,7 @@ static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst #define VOLUME_ADDIN(icode, ptr, dst, src, vol) \ _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol)) #define VOLUME_OUT(icode, ptr, dst, src, vol) \ - _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol)) + _volume(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol)) #define _SWITCH(icode, ptr, dst, src, sw) \ OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw); #define SWITCH(icode, ptr, dst, src, sw) \ @@ -1852,7 +1787,7 @@ static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, tmp, playback, capture; - u32 ptr; + u32 ptr, ptr_skip; struct snd_emu10k1_fx8010_code *icode; struct snd_emu10k1_fx8010_pcm_rec *ipcm = NULL; struct snd_emu10k1_fx8010_control_gpr *controls = NULL, *ctl; @@ -1895,7 +1830,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* we have 12 inputs */ playback = SND_EMU10K1_INPUTS; /* we have 6 playback channels and tone control doubles */ - capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); + capture = playback + SND_EMU10K1_PLAYBACK_CHANNELS; gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS; tmp = 0x88; /* we need 4 temporary GPR */ /* from 0x8c to 0xff is the area for tone control */ @@ -1903,18 +1838,18 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* * Process FX Buses */ - OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004); + OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000008); OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */ OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */ - OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000004); - OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000004); + OP(icode, &ptr, iMACINT0, GPR(10), C_00000000, FXBUS(FXBUS_PCM_LEFT_FRONT), C_00000008); + OP(icode, &ptr, iMACINT0, GPR(11), C_00000000, FXBUS(FXBUS_PCM_RIGHT_FRONT), C_00000008); /* Raw S/PDIF PCM */ ipcm->substream = 0; @@ -2008,7 +1943,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* Wave Center/LFE Playback Volume */ OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000); - OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002); + OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000004); VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr); snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0); VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr); @@ -2199,13 +2134,6 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* * Process tone control */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */ - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */ - ctl = &controls[i + 0]; ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, "Tone Control - Bass"); @@ -2237,12 +2165,19 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j; } } + i += 2; + + OP(icode, &ptr, iACC3, C_00000000, GPR(gpr), C_00000000, C_00000000); + snd_emu10k1_init_mono_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0); + gpr++; + OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr)); + ptr_skip = ptr; for (z = 0; z < 3; z++) { /* front/rear/center-lfe */ int j, k, l, d; for (j = 0; j < 2; j++) { /* left/right */ k = 0xa0 + (z * 8) + (j * 4); l = 0xd0 + (z * 8) + (j * 4); - d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j; + d = playback + z * 2 + j; OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j)); OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j)); @@ -2264,20 +2199,11 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) break; } } - i += 2; + gpr_map[gpr++] = ptr - ptr_skip; #undef BASS_GPR #undef TREBLE_GPR - for (z = 0; z < 6; z++) { - SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0); - SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0); - SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); - OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); - } - snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0); - gpr += 2; - /* * Process outputs */ @@ -2285,7 +2211,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* AC'97 Playback Volume */ for (z = 0; z < 2; z++) - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + z), C_00000000, C_00000000); } if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) { @@ -2294,7 +2220,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) for (z = 0; z < 2; z++) { SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z); SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z); - SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); + SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); #ifdef EMU10K1_CAPTURE_DIGITAL_OUT OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); @@ -2309,9 +2235,9 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* Headphone Playback Volume */ for (z = 0; z < 2; z++) { - SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z); + SWITCH(icode, &ptr, tmp + 0, playback + 4 + z, gpr + 2 + z); SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z); - SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); + SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000); VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z); } @@ -2328,29 +2254,29 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R))) for (z = 0; z < 2; z++) - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000); if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R))) for (z = 0; z < 2; z++) - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + 2 + z), C_00000000, C_00000000); if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) { #ifndef EMU10K1_CENTER_LFE_FROM_FRONT - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000); - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 4), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 4), C_00000000, C_00000000); #else - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000); - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + 0), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + 0), C_00000000, C_00000000); #endif } if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) { #ifndef EMU10K1_CENTER_LFE_FROM_FRONT - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000); - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 5), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 5), C_00000000, C_00000000); #else - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000); - OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + 1), C_00000000, C_00000000); + OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + 1), C_00000000, C_00000000); #endif } diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 3ebc7c36a444..20a0b3afc8a5 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -29,6 +29,24 @@ static const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ + +static int add_ctls(struct snd_emu10k1 *emu, const struct snd_kcontrol_new *tpl, + const char * const *ctls, unsigned nctls) +{ + struct snd_kcontrol_new kctl = *tpl; + int err; + + for (unsigned i = 0; i < nctls; i++) { + kctl.name = ctls[i]; + kctl.private_value = i; + err = snd_ctl_add(emu->card, snd_ctl_new1(&kctl, emu)); + if (err < 0) + return err; + } + return 0; +} + + static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -41,17 +59,14 @@ static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned long flags; /* Limit: emu->spdif_bits */ if (idx >= 3) return -EINVAL; - spin_lock_irqsave(&emu->reg_lock, flags); ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -65,292 +80,354 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, return 0; } +#define PAIR_PS(base, one, two, sfx) base " " one sfx, base " " two sfx +#define LR_PS(base, sfx) PAIR_PS(base, "Left", "Right", sfx) + +#define ADAT_PS(pfx, sfx) \ + pfx "ADAT 0" sfx, pfx "ADAT 1" sfx, pfx "ADAT 2" sfx, pfx "ADAT 3" sfx, \ + pfx "ADAT 4" sfx, pfx "ADAT 5" sfx, pfx "ADAT 6" sfx, pfx "ADAT 7" sfx + +#define PAIR_REGS(base, one, two) \ + base ## one ## 1, \ + base ## two ## 1 + +#define LR_REGS(base) PAIR_REGS(base, _LEFT, _RIGHT) + +#define ADAT_REGS(base) \ + base+0, base+1, base+2, base+3, base+4, base+5, base+6, base+7 + /* - * Items labels in enum mixer controls assigning source data to - * each destination + * List of data sources available for each destination */ + +#define DSP_TEXTS \ + "DSP 0", "DSP 1", "DSP 2", "DSP 3", "DSP 4", "DSP 5", "DSP 6", "DSP 7", \ + "DSP 8", "DSP 9", "DSP 10", "DSP 11", "DSP 12", "DSP 13", "DSP 14", "DSP 15", \ + "DSP 16", "DSP 17", "DSP 18", "DSP 19", "DSP 20", "DSP 21", "DSP 22", "DSP 23", \ + "DSP 24", "DSP 25", "DSP 26", "DSP 27", "DSP 28", "DSP 29", "DSP 30", "DSP 31" + +#define PAIR_TEXTS(base, one, two) PAIR_PS(base, one, two, "") +#define LR_TEXTS(base) LR_PS(base, "") +#define ADAT_TEXTS(pfx) ADAT_PS(pfx, "") + +#define EMU32_SRC_REGS \ + EMU_SRC_ALICE_EMU32A, \ + EMU_SRC_ALICE_EMU32A+1, \ + EMU_SRC_ALICE_EMU32A+2, \ + EMU_SRC_ALICE_EMU32A+3, \ + EMU_SRC_ALICE_EMU32A+4, \ + EMU_SRC_ALICE_EMU32A+5, \ + EMU_SRC_ALICE_EMU32A+6, \ + EMU_SRC_ALICE_EMU32A+7, \ + EMU_SRC_ALICE_EMU32A+8, \ + EMU_SRC_ALICE_EMU32A+9, \ + EMU_SRC_ALICE_EMU32A+0xa, \ + EMU_SRC_ALICE_EMU32A+0xb, \ + EMU_SRC_ALICE_EMU32A+0xc, \ + EMU_SRC_ALICE_EMU32A+0xd, \ + EMU_SRC_ALICE_EMU32A+0xe, \ + EMU_SRC_ALICE_EMU32A+0xf, \ + EMU_SRC_ALICE_EMU32B, \ + EMU_SRC_ALICE_EMU32B+1, \ + EMU_SRC_ALICE_EMU32B+2, \ + EMU_SRC_ALICE_EMU32B+3, \ + EMU_SRC_ALICE_EMU32B+4, \ + EMU_SRC_ALICE_EMU32B+5, \ + EMU_SRC_ALICE_EMU32B+6, \ + EMU_SRC_ALICE_EMU32B+7, \ + EMU_SRC_ALICE_EMU32B+8, \ + EMU_SRC_ALICE_EMU32B+9, \ + EMU_SRC_ALICE_EMU32B+0xa, \ + EMU_SRC_ALICE_EMU32B+0xb, \ + EMU_SRC_ALICE_EMU32B+0xc, \ + EMU_SRC_ALICE_EMU32B+0xd, \ + EMU_SRC_ALICE_EMU32B+0xe, \ + EMU_SRC_ALICE_EMU32B+0xf + +/* 1010 rev1 */ + +#define EMU1010_COMMON_TEXTS \ + "Silence", \ + PAIR_TEXTS("Dock Mic", "A", "B"), \ + LR_TEXTS("Dock ADC1"), \ + LR_TEXTS("Dock ADC2"), \ + LR_TEXTS("Dock ADC3"), \ + LR_TEXTS("0202 ADC"), \ + LR_TEXTS("1010 SPDIF"), \ + ADAT_TEXTS("1010 ") + static const char * const emu1010_src_texts[] = { - "Silence", - "Dock Mic A", - "Dock Mic B", - "Dock ADC1 Left", - "Dock ADC1 Right", - "Dock ADC2 Left", - "Dock ADC2 Right", - "Dock ADC3 Left", - "Dock ADC3 Right", - "0202 ADC Left", - "0202 ADC Right", - "0202 SPDIF Left", - "0202 SPDIF Right", - "ADAT 0", - "ADAT 1", - "ADAT 2", - "ADAT 3", - "ADAT 4", - "ADAT 5", - "ADAT 6", - "ADAT 7", - "DSP 0", - "DSP 1", - "DSP 2", - "DSP 3", - "DSP 4", - "DSP 5", - "DSP 6", - "DSP 7", - "DSP 8", - "DSP 9", - "DSP 10", - "DSP 11", - "DSP 12", - "DSP 13", - "DSP 14", - "DSP 15", - "DSP 16", - "DSP 17", - "DSP 18", - "DSP 19", - "DSP 20", - "DSP 21", - "DSP 22", - "DSP 23", - "DSP 24", - "DSP 25", - "DSP 26", - "DSP 27", - "DSP 28", - "DSP 29", - "DSP 30", - "DSP 31", + EMU1010_COMMON_TEXTS, + DSP_TEXTS, +}; + +static const unsigned short emu1010_src_regs[] = { + EMU_SRC_SILENCE, + PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), + LR_REGS(EMU_SRC_DOCK_ADC1), + LR_REGS(EMU_SRC_DOCK_ADC2), + LR_REGS(EMU_SRC_DOCK_ADC3), + LR_REGS(EMU_SRC_HAMOA_ADC), + LR_REGS(EMU_SRC_HANA_SPDIF), + ADAT_REGS(EMU_SRC_HANA_ADAT), + EMU32_SRC_REGS, }; +static_assert(ARRAY_SIZE(emu1010_src_regs) == ARRAY_SIZE(emu1010_src_texts)); + +/* 1010 rev2 */ + +#define EMU1010b_COMMON_TEXTS \ + "Silence", \ + PAIR_TEXTS("Dock Mic", "A", "B"), \ + LR_TEXTS("Dock ADC1"), \ + LR_TEXTS("Dock ADC2"), \ + LR_TEXTS("0202 ADC"), \ + LR_TEXTS("Dock SPDIF"), \ + LR_TEXTS("1010 SPDIF"), \ + ADAT_TEXTS("Dock "), \ + ADAT_TEXTS("1010 ") + +static const char * const emu1010b_src_texts[] = { + EMU1010b_COMMON_TEXTS, + DSP_TEXTS, +}; + +static const unsigned short emu1010b_src_regs[] = { + EMU_SRC_SILENCE, + PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), + LR_REGS(EMU_SRC_DOCK_ADC1), + LR_REGS(EMU_SRC_DOCK_ADC2), + LR_REGS(EMU_SRC_HAMOA_ADC), + LR_REGS(EMU_SRC_MDOCK_SPDIF), + LR_REGS(EMU_SRC_HANA_SPDIF), + ADAT_REGS(EMU_SRC_MDOCK_ADAT), + ADAT_REGS(EMU_SRC_HANA_ADAT), + EMU32_SRC_REGS, +}; +static_assert(ARRAY_SIZE(emu1010b_src_regs) == ARRAY_SIZE(emu1010b_src_texts)); /* 1616(m) cardbus */ +#define EMU1616_COMMON_TEXTS \ + "Silence", \ + PAIR_TEXTS("Mic", "A", "B"), \ + LR_TEXTS("ADC1"), \ + LR_TEXTS("ADC2"), \ + LR_TEXTS("SPDIF"), \ + ADAT_TEXTS("") + static const char * const emu1616_src_texts[] = { - "Silence", - "Dock Mic A", - "Dock Mic B", - "Dock ADC1 Left", - "Dock ADC1 Right", - "Dock ADC2 Left", - "Dock ADC2 Right", - "Dock SPDIF Left", - "Dock SPDIF Right", - "ADAT 0", - "ADAT 1", - "ADAT 2", - "ADAT 3", - "ADAT 4", - "ADAT 5", - "ADAT 6", - "ADAT 7", - "DSP 0", - "DSP 1", - "DSP 2", - "DSP 3", - "DSP 4", - "DSP 5", - "DSP 6", - "DSP 7", - "DSP 8", - "DSP 9", - "DSP 10", - "DSP 11", - "DSP 12", - "DSP 13", - "DSP 14", - "DSP 15", - "DSP 16", - "DSP 17", - "DSP 18", - "DSP 19", - "DSP 20", - "DSP 21", - "DSP 22", - "DSP 23", - "DSP 24", - "DSP 25", - "DSP 26", - "DSP 27", - "DSP 28", - "DSP 29", - "DSP 30", - "DSP 31", + EMU1616_COMMON_TEXTS, + DSP_TEXTS, }; +static const unsigned short emu1616_src_regs[] = { + EMU_SRC_SILENCE, + PAIR_REGS(EMU_SRC_DOCK_MIC, _A, _B), + LR_REGS(EMU_SRC_DOCK_ADC1), + LR_REGS(EMU_SRC_DOCK_ADC2), + LR_REGS(EMU_SRC_MDOCK_SPDIF), + ADAT_REGS(EMU_SRC_MDOCK_ADAT), + EMU32_SRC_REGS, +}; +static_assert(ARRAY_SIZE(emu1616_src_regs) == ARRAY_SIZE(emu1616_src_texts)); -/* - * List of data sources available for each destination - */ -static const unsigned int emu1010_src_regs[] = { - EMU_SRC_SILENCE,/* 0 */ - EMU_SRC_DOCK_MIC_A1, /* 1 */ - EMU_SRC_DOCK_MIC_B1, /* 2 */ - EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ - EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ - EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ - EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ - EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ - EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ - EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ - EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ - EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ - EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ - EMU_SRC_HANA_ADAT, /* 13 */ - EMU_SRC_HANA_ADAT+1, /* 14 */ - EMU_SRC_HANA_ADAT+2, /* 15 */ - EMU_SRC_HANA_ADAT+3, /* 16 */ - EMU_SRC_HANA_ADAT+4, /* 17 */ - EMU_SRC_HANA_ADAT+5, /* 18 */ - EMU_SRC_HANA_ADAT+6, /* 19 */ - EMU_SRC_HANA_ADAT+7, /* 20 */ - EMU_SRC_ALICE_EMU32A, /* 21 */ - EMU_SRC_ALICE_EMU32A+1, /* 22 */ - EMU_SRC_ALICE_EMU32A+2, /* 23 */ - EMU_SRC_ALICE_EMU32A+3, /* 24 */ - EMU_SRC_ALICE_EMU32A+4, /* 25 */ - EMU_SRC_ALICE_EMU32A+5, /* 26 */ - EMU_SRC_ALICE_EMU32A+6, /* 27 */ - EMU_SRC_ALICE_EMU32A+7, /* 28 */ - EMU_SRC_ALICE_EMU32A+8, /* 29 */ - EMU_SRC_ALICE_EMU32A+9, /* 30 */ - EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ - EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ - EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ - EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ - EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ - EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ - EMU_SRC_ALICE_EMU32B, /* 37 */ - EMU_SRC_ALICE_EMU32B+1, /* 38 */ - EMU_SRC_ALICE_EMU32B+2, /* 39 */ - EMU_SRC_ALICE_EMU32B+3, /* 40 */ - EMU_SRC_ALICE_EMU32B+4, /* 41 */ - EMU_SRC_ALICE_EMU32B+5, /* 42 */ - EMU_SRC_ALICE_EMU32B+6, /* 43 */ - EMU_SRC_ALICE_EMU32B+7, /* 44 */ - EMU_SRC_ALICE_EMU32B+8, /* 45 */ - EMU_SRC_ALICE_EMU32B+9, /* 46 */ - EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ - EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ - EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ - EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ - EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ - EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ +/* 0404 rev1 & rev2 */ + +#define EMU0404_COMMON_TEXTS \ + "Silence", \ + LR_TEXTS("ADC"), \ + LR_TEXTS("SPDIF") + +static const char * const emu0404_src_texts[] = { + EMU0404_COMMON_TEXTS, + DSP_TEXTS, }; -/* 1616(m) cardbus */ -static const unsigned int emu1616_src_regs[] = { +static const unsigned short emu0404_src_regs[] = { EMU_SRC_SILENCE, - EMU_SRC_DOCK_MIC_A1, - EMU_SRC_DOCK_MIC_B1, - EMU_SRC_DOCK_ADC1_LEFT1, - EMU_SRC_DOCK_ADC1_RIGHT1, - EMU_SRC_DOCK_ADC2_LEFT1, - EMU_SRC_DOCK_ADC2_RIGHT1, - EMU_SRC_MDOCK_SPDIF_LEFT1, - EMU_SRC_MDOCK_SPDIF_RIGHT1, - EMU_SRC_MDOCK_ADAT, - EMU_SRC_MDOCK_ADAT+1, - EMU_SRC_MDOCK_ADAT+2, - EMU_SRC_MDOCK_ADAT+3, - EMU_SRC_MDOCK_ADAT+4, - EMU_SRC_MDOCK_ADAT+5, - EMU_SRC_MDOCK_ADAT+6, - EMU_SRC_MDOCK_ADAT+7, - EMU_SRC_ALICE_EMU32A, - EMU_SRC_ALICE_EMU32A+1, - EMU_SRC_ALICE_EMU32A+2, - EMU_SRC_ALICE_EMU32A+3, - EMU_SRC_ALICE_EMU32A+4, - EMU_SRC_ALICE_EMU32A+5, - EMU_SRC_ALICE_EMU32A+6, - EMU_SRC_ALICE_EMU32A+7, - EMU_SRC_ALICE_EMU32A+8, - EMU_SRC_ALICE_EMU32A+9, - EMU_SRC_ALICE_EMU32A+0xa, - EMU_SRC_ALICE_EMU32A+0xb, - EMU_SRC_ALICE_EMU32A+0xc, - EMU_SRC_ALICE_EMU32A+0xd, - EMU_SRC_ALICE_EMU32A+0xe, - EMU_SRC_ALICE_EMU32A+0xf, - EMU_SRC_ALICE_EMU32B, - EMU_SRC_ALICE_EMU32B+1, - EMU_SRC_ALICE_EMU32B+2, - EMU_SRC_ALICE_EMU32B+3, - EMU_SRC_ALICE_EMU32B+4, - EMU_SRC_ALICE_EMU32B+5, - EMU_SRC_ALICE_EMU32B+6, - EMU_SRC_ALICE_EMU32B+7, - EMU_SRC_ALICE_EMU32B+8, - EMU_SRC_ALICE_EMU32B+9, - EMU_SRC_ALICE_EMU32B+0xa, - EMU_SRC_ALICE_EMU32B+0xb, - EMU_SRC_ALICE_EMU32B+0xc, - EMU_SRC_ALICE_EMU32B+0xd, - EMU_SRC_ALICE_EMU32B+0xe, - EMU_SRC_ALICE_EMU32B+0xf, + LR_REGS(EMU_SRC_HAMOA_ADC), + LR_REGS(EMU_SRC_HANA_SPDIF), + EMU32_SRC_REGS, }; +static_assert(ARRAY_SIZE(emu0404_src_regs) == ARRAY_SIZE(emu0404_src_texts)); /* * Data destinations - physical EMU outputs. * Each destination has an enum mixer control to choose a data source */ -static const unsigned int emu1010_output_dst[] = { - EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ - EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ - EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ - EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ - EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ - EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ - EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ - EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ - EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ - EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ - EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ - EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ - EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ - EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ - EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ - EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ - EMU_DST_HANA_ADAT, /* 16 */ - EMU_DST_HANA_ADAT+1, /* 17 */ - EMU_DST_HANA_ADAT+2, /* 18 */ - EMU_DST_HANA_ADAT+3, /* 19 */ - EMU_DST_HANA_ADAT+4, /* 20 */ - EMU_DST_HANA_ADAT+5, /* 21 */ - EMU_DST_HANA_ADAT+6, /* 22 */ - EMU_DST_HANA_ADAT+7, /* 23 */ + +#define LR_CTLS(base) LR_PS(base, " Playback Enum") +#define ADAT_CTLS(pfx) ADAT_PS(pfx, " Playback Enum") + +/* 1010 rev1 */ + +static const char * const emu1010_output_texts[] = { + LR_CTLS("Dock DAC1"), + LR_CTLS("Dock DAC2"), + LR_CTLS("Dock DAC3"), + LR_CTLS("Dock DAC4"), + LR_CTLS("Dock Phones"), + LR_CTLS("Dock SPDIF"), + LR_CTLS("0202 DAC"), + LR_CTLS("1010 SPDIF"), + ADAT_CTLS("1010 "), +}; +static_assert(ARRAY_SIZE(emu1010_output_texts) <= NUM_OUTPUT_DESTS); + +static const unsigned short emu1010_output_dst[] = { + LR_REGS(EMU_DST_DOCK_DAC1), + LR_REGS(EMU_DST_DOCK_DAC2), + LR_REGS(EMU_DST_DOCK_DAC3), + LR_REGS(EMU_DST_DOCK_DAC4), + LR_REGS(EMU_DST_DOCK_PHONES), + LR_REGS(EMU_DST_DOCK_SPDIF), + LR_REGS(EMU_DST_HAMOA_DAC), + LR_REGS(EMU_DST_HANA_SPDIF), + ADAT_REGS(EMU_DST_HANA_ADAT), +}; +static_assert(ARRAY_SIZE(emu1010_output_dst) == ARRAY_SIZE(emu1010_output_texts)); + +static const unsigned short emu1010_output_dflt[] = { + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, + EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, +}; +static_assert(ARRAY_SIZE(emu1010_output_dflt) == ARRAY_SIZE(emu1010_output_dst)); + +/* 1010 rev2 */ + +static const char * const snd_emu1010b_output_texts[] = { + LR_CTLS("Dock DAC1"), + LR_CTLS("Dock DAC2"), + LR_CTLS("Dock DAC3"), + LR_CTLS("Dock SPDIF"), + ADAT_CTLS("Dock "), + LR_CTLS("0202 DAC"), + LR_CTLS("1010 SPDIF"), + ADAT_CTLS("1010 "), +}; +static_assert(ARRAY_SIZE(snd_emu1010b_output_texts) <= NUM_OUTPUT_DESTS); + +static const unsigned short emu1010b_output_dst[] = { + LR_REGS(EMU_DST_DOCK_DAC1), + LR_REGS(EMU_DST_DOCK_DAC2), + LR_REGS(EMU_DST_DOCK_DAC3), + LR_REGS(EMU_DST_MDOCK_SPDIF), + ADAT_REGS(EMU_DST_MDOCK_ADAT), + LR_REGS(EMU_DST_HAMOA_DAC), + LR_REGS(EMU_DST_HANA_SPDIF), + ADAT_REGS(EMU_DST_HANA_ADAT), +}; +static_assert(ARRAY_SIZE(emu1010b_output_dst) == ARRAY_SIZE(snd_emu1010b_output_texts)); + +static const unsigned short emu1010b_output_dflt[] = { + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, }; /* 1616(m) cardbus */ -static const unsigned int emu1616_output_dst[] = { - EMU_DST_DOCK_DAC1_LEFT1, - EMU_DST_DOCK_DAC1_RIGHT1, - EMU_DST_DOCK_DAC2_LEFT1, - EMU_DST_DOCK_DAC2_RIGHT1, - EMU_DST_DOCK_DAC3_LEFT1, - EMU_DST_DOCK_DAC3_RIGHT1, - EMU_DST_MDOCK_SPDIF_LEFT1, - EMU_DST_MDOCK_SPDIF_RIGHT1, - EMU_DST_MDOCK_ADAT, - EMU_DST_MDOCK_ADAT+1, - EMU_DST_MDOCK_ADAT+2, - EMU_DST_MDOCK_ADAT+3, - EMU_DST_MDOCK_ADAT+4, - EMU_DST_MDOCK_ADAT+5, - EMU_DST_MDOCK_ADAT+6, - EMU_DST_MDOCK_ADAT+7, - EMU_DST_MANA_DAC_LEFT, - EMU_DST_MANA_DAC_RIGHT, + +static const char * const snd_emu1616_output_texts[] = { + LR_CTLS("Dock DAC1"), + LR_CTLS("Dock DAC2"), + LR_CTLS("Dock DAC3"), + LR_CTLS("Dock SPDIF"), + ADAT_CTLS("Dock "), + LR_CTLS("Mana DAC"), +}; +static_assert(ARRAY_SIZE(snd_emu1616_output_texts) <= NUM_OUTPUT_DESTS); + +static const unsigned short emu1616_output_dst[] = { + LR_REGS(EMU_DST_DOCK_DAC1), + LR_REGS(EMU_DST_DOCK_DAC2), + LR_REGS(EMU_DST_DOCK_DAC3), + LR_REGS(EMU_DST_MDOCK_SPDIF), + ADAT_REGS(EMU_DST_MDOCK_ADAT), + EMU_DST_MANA_DAC_LEFT, EMU_DST_MANA_DAC_RIGHT, +}; +static_assert(ARRAY_SIZE(emu1616_output_dst) == ARRAY_SIZE(snd_emu1616_output_texts)); + +static const unsigned short emu1616_output_dflt[] = { + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, EMU_SRC_ALICE_EMU32A+2, EMU_SRC_ALICE_EMU32A+3, + EMU_SRC_ALICE_EMU32A+4, EMU_SRC_ALICE_EMU32A+5, EMU_SRC_ALICE_EMU32A+6, EMU_SRC_ALICE_EMU32A+7, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, +}; +static_assert(ARRAY_SIZE(emu1616_output_dflt) == ARRAY_SIZE(emu1616_output_dst)); + +/* 0404 rev1 & rev2 */ + +static const char * const snd_emu0404_output_texts[] = { + LR_CTLS("DAC"), + LR_CTLS("SPDIF"), +}; +static_assert(ARRAY_SIZE(snd_emu0404_output_texts) <= NUM_OUTPUT_DESTS); + +static const unsigned short emu0404_output_dst[] = { + LR_REGS(EMU_DST_HAMOA_DAC), + LR_REGS(EMU_DST_HANA_SPDIF), +}; +static_assert(ARRAY_SIZE(emu0404_output_dst) == ARRAY_SIZE(snd_emu0404_output_texts)); + +static const unsigned short emu0404_output_dflt[] = { + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, + EMU_SRC_ALICE_EMU32A+0, EMU_SRC_ALICE_EMU32A+1, }; +static_assert(ARRAY_SIZE(emu0404_output_dflt) == ARRAY_SIZE(emu0404_output_dst)); /* * Data destinations - FPGA outputs going to Alice2 (Audigy) for * capture (EMU32 + I2S links) * Each destination has an enum mixer control to choose a data source */ -static const unsigned int emu1010_input_dst[] = { + +static const char * const emu1010_input_texts[] = { + "DSP 0 Capture Enum", + "DSP 1 Capture Enum", + "DSP 2 Capture Enum", + "DSP 3 Capture Enum", + "DSP 4 Capture Enum", + "DSP 5 Capture Enum", + "DSP 6 Capture Enum", + "DSP 7 Capture Enum", + "DSP 8 Capture Enum", + "DSP 9 Capture Enum", + "DSP A Capture Enum", + "DSP B Capture Enum", + "DSP C Capture Enum", + "DSP D Capture Enum", + "DSP E Capture Enum", + "DSP F Capture Enum", + /* These exist only on rev1 EMU1010 cards. */ + "DSP 10 Capture Enum", + "DSP 11 Capture Enum", + "DSP 12 Capture Enum", + "DSP 13 Capture Enum", + "DSP 14 Capture Enum", + "DSP 15 Capture Enum", +}; +static_assert(ARRAY_SIZE(emu1010_input_texts) <= NUM_INPUT_DESTS); + +static const unsigned short emu1010_input_dst[] = { EMU_DST_ALICE2_EMU32_0, EMU_DST_ALICE2_EMU32_1, EMU_DST_ALICE2_EMU32_2, @@ -375,29 +452,199 @@ static const unsigned int emu1010_input_dst[] = { EMU_DST_ALICE_I2S2_LEFT, EMU_DST_ALICE_I2S2_RIGHT, }; +static_assert(ARRAY_SIZE(emu1010_input_dst) == ARRAY_SIZE(emu1010_input_texts)); + +static const unsigned short emu1010_input_dflt[] = { + EMU_SRC_DOCK_MIC_A1, + EMU_SRC_DOCK_MIC_B1, + EMU_SRC_HAMOA_ADC_LEFT1, + EMU_SRC_HAMOA_ADC_RIGHT1, + EMU_SRC_DOCK_ADC1_LEFT1, + EMU_SRC_DOCK_ADC1_RIGHT1, + EMU_SRC_DOCK_ADC2_LEFT1, + EMU_SRC_DOCK_ADC2_RIGHT1, + /* Pavel Hofman - setting defaults for all capture channels. + * Defaults only, users will set their own values anyways, let's + * just copy/paste. */ + EMU_SRC_DOCK_MIC_A1, + EMU_SRC_DOCK_MIC_B1, + EMU_SRC_HAMOA_ADC_LEFT1, + EMU_SRC_HAMOA_ADC_RIGHT1, + EMU_SRC_DOCK_ADC1_LEFT1, + EMU_SRC_DOCK_ADC1_RIGHT1, + EMU_SRC_DOCK_ADC2_LEFT1, + EMU_SRC_DOCK_ADC2_RIGHT1, + + EMU_SRC_DOCK_ADC1_LEFT1, + EMU_SRC_DOCK_ADC1_RIGHT1, + EMU_SRC_DOCK_ADC2_LEFT1, + EMU_SRC_DOCK_ADC2_RIGHT1, + EMU_SRC_DOCK_ADC3_LEFT1, + EMU_SRC_DOCK_ADC3_RIGHT1, +}; +static_assert(ARRAY_SIZE(emu1010_input_dflt) == ARRAY_SIZE(emu1010_input_dst)); + +static const unsigned short emu0404_input_dflt[] = { + EMU_SRC_HAMOA_ADC_LEFT1, + EMU_SRC_HAMOA_ADC_RIGHT1, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_HANA_SPDIF_LEFT1, + EMU_SRC_HANA_SPDIF_RIGHT1, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, + EMU_SRC_SILENCE, +}; + +struct snd_emu1010_routing_info { + const char * const *src_texts; + const char * const *out_texts; + const unsigned short *src_regs; + const unsigned short *out_regs; + const unsigned short *in_regs; + const unsigned short *out_dflts; + const unsigned short *in_dflts; + unsigned n_srcs; + unsigned n_outs; + unsigned n_ins; +}; + +static const struct snd_emu1010_routing_info emu1010_routing_info[] = { + { + /* rev1 1010 */ + .src_regs = emu1010_src_regs, + .src_texts = emu1010_src_texts, + .n_srcs = ARRAY_SIZE(emu1010_src_texts), + + .out_dflts = emu1010_output_dflt, + .out_regs = emu1010_output_dst, + .out_texts = emu1010_output_texts, + .n_outs = ARRAY_SIZE(emu1010_output_dst), + + .in_dflts = emu1010_input_dflt, + .in_regs = emu1010_input_dst, + .n_ins = ARRAY_SIZE(emu1010_input_dst), + }, + { + /* rev2 1010 */ + .src_regs = emu1010b_src_regs, + .src_texts = emu1010b_src_texts, + .n_srcs = ARRAY_SIZE(emu1010b_src_texts), + + .out_dflts = emu1010b_output_dflt, + .out_regs = emu1010b_output_dst, + .out_texts = snd_emu1010b_output_texts, + .n_outs = ARRAY_SIZE(emu1010b_output_dst), + + .in_dflts = emu1010_input_dflt, + .in_regs = emu1010_input_dst, + .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, + }, + { + /* 1616(m) cardbus */ + .src_regs = emu1616_src_regs, + .src_texts = emu1616_src_texts, + .n_srcs = ARRAY_SIZE(emu1616_src_texts), + + .out_dflts = emu1616_output_dflt, + .out_regs = emu1616_output_dst, + .out_texts = snd_emu1616_output_texts, + .n_outs = ARRAY_SIZE(emu1616_output_dst), + + .in_dflts = emu1010_input_dflt, + .in_regs = emu1010_input_dst, + .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, + }, + { + /* 0404 */ + .src_regs = emu0404_src_regs, + .src_texts = emu0404_src_texts, + .n_srcs = ARRAY_SIZE(emu0404_src_texts), + + .out_dflts = emu0404_output_dflt, + .out_regs = emu0404_output_dst, + .out_texts = snd_emu0404_output_texts, + .n_outs = ARRAY_SIZE(emu0404_output_dflt), + + .in_dflts = emu0404_input_dflt, + .in_regs = emu1010_input_dst, + .n_ins = ARRAY_SIZE(emu1010_input_dst) - 6, + }, +}; + +static unsigned emu1010_idx(struct snd_emu10k1 *emu) +{ + return emu->card_capabilities->emu_model - 1; +} + +static void snd_emu1010_output_source_apply(struct snd_emu10k1 *emu, + int channel, int src) +{ + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + + snd_emu1010_fpga_link_dst_src_write(emu, + emu_ri->out_regs[channel], emu_ri->src_regs[src]); +} + +static void snd_emu1010_input_source_apply(struct snd_emu10k1 *emu, + int channel, int src) +{ + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + + snd_emu1010_fpga_link_dst_src_write(emu, + emu_ri->in_regs[channel], emu_ri->src_regs[src]); +} + +static void snd_emu1010_apply_sources(struct snd_emu10k1 *emu) +{ + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + + for (unsigned i = 0; i < emu_ri->n_outs; i++) + snd_emu1010_output_source_apply( + emu, i, emu->emu1010.output_source[i]); + for (unsigned i = 0; i < emu_ri->n_ins; i++) + snd_emu1010_input_source_apply( + emu, i, emu->emu1010.input_source[i]); +} + +static u8 emu1010_map_source(const struct snd_emu1010_routing_info *emu_ri, + unsigned val) +{ + for (unsigned i = 0; i < emu_ri->n_srcs; i++) + if (val == emu_ri->src_regs[i]) + return i; + return 0; +} static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) - return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); - else - return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); + return snd_ctl_enum_info(uinfo, 1, emu_ri->n_srcs, emu_ri->src_texts); } static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int channel; + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + unsigned channel = kcontrol->private_value; - channel = (kcontrol->private_value) & 0xff; - /* Limit: emu1010_output_dst, emu->emu1010.output_source */ - if (channel >= 24 || - (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && - channel >= 18)) + if (channel >= emu_ri->n_outs) return -EINVAL; ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; return 0; @@ -407,41 +654,41 @@ static int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int val; - unsigned int channel; + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + unsigned val = ucontrol->value.enumerated.item[0]; + unsigned channel = kcontrol->private_value; + int change; - val = ucontrol->value.enumerated.item[0]; - if (val >= 53 || - (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && - val >= 49)) + if (val >= emu_ri->n_srcs) return -EINVAL; - channel = (kcontrol->private_value) & 0xff; - /* Limit: emu1010_output_dst, emu->emu1010.output_source */ - if (channel >= 24 || - (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && - channel >= 18)) + if (channel >= emu_ri->n_outs) return -EINVAL; - if (emu->emu1010.output_source[channel] == val) - return 0; - emu->emu1010.output_source[channel] = val; - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) - snd_emu1010_fpga_link_dst_src_write(emu, - emu1616_output_dst[channel], emu1616_src_regs[val]); - else - snd_emu1010_fpga_link_dst_src_write(emu, - emu1010_output_dst[channel], emu1010_src_regs[val]); - return 1; + change = (emu->emu1010.output_source[channel] != val); + if (change) { + emu->emu1010.output_source[channel] = val; + snd_emu1010_output_source_apply(emu, channel, val); + } + return change; } +static const struct snd_kcontrol_new emu1010_output_source_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_emu1010_input_output_source_info, + .get = snd_emu1010_output_source_get, + .put = snd_emu1010_output_source_put +}; + static int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int channel; + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + unsigned channel = kcontrol->private_value; - channel = (kcontrol->private_value) & 0xff; - /* Limit: emu1010_input_dst, emu->emu1010.input_source */ - if (channel >= 22) + if (channel >= emu_ri->n_ins) return -EINVAL; ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; return 0; @@ -451,134 +698,69 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int val; - unsigned int channel; + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + unsigned val = ucontrol->value.enumerated.item[0]; + unsigned channel = kcontrol->private_value; + int change; - val = ucontrol->value.enumerated.item[0]; - if (val >= 53 || - (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && - val >= 49)) + if (val >= emu_ri->n_srcs) return -EINVAL; - channel = (kcontrol->private_value) & 0xff; - /* Limit: emu1010_input_dst, emu->emu1010.input_source */ - if (channel >= 22) + if (channel >= emu_ri->n_ins) return -EINVAL; - if (emu->emu1010.input_source[channel] == val) - return 0; - emu->emu1010.input_source[channel] = val; - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) - snd_emu1010_fpga_link_dst_src_write(emu, - emu1010_input_dst[channel], emu1616_src_regs[val]); - else - snd_emu1010_fpga_link_dst_src_write(emu, - emu1010_input_dst[channel], emu1010_src_regs[val]); - return 1; -} - -#define EMU1010_SOURCE_OUTPUT(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_emu1010_input_output_source_info, \ - .get = snd_emu1010_output_source_get, \ - .put = snd_emu1010_output_source_put, \ - .private_value = chid \ -} - -static const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { - EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), - EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), - EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), - EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), - EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), - EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), - EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), - EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), - EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), - EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), - EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), - EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), - EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), - EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), - EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), - EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), - EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), - EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), + change = (emu->emu1010.input_source[channel] != val); + if (change) { + emu->emu1010.input_source[channel] = val; + snd_emu1010_input_source_apply(emu, channel, val); + } + return change; +} + +static const struct snd_kcontrol_new emu1010_input_source_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_emu1010_input_output_source_info, + .get = snd_emu1010_input_source_get, + .put = snd_emu1010_input_source_put }; +static int add_emu1010_source_mixers(struct snd_emu10k1 *emu) +{ + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu1010_idx(emu)]; + int err; -/* 1616(m) cardbus */ -static const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { - EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), - EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), - EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), - EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), - EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), - EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), - EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), - EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), - EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), - EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), - EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), - EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), - EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), - EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), - EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), -}; + err = add_ctls(emu, &emu1010_output_source_ctl, + emu_ri->out_texts, emu_ri->n_outs); + if (err < 0) + return err; + err = add_ctls(emu, &emu1010_input_source_ctl, + emu1010_input_texts, emu_ri->n_ins); + return err; +} -#define EMU1010_SOURCE_INPUT(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_emu1010_input_output_source_info, \ - .get = snd_emu1010_input_source_get, \ - .put = snd_emu1010_input_source_put, \ - .private_value = chid \ -} - -static const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { - EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), - EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), - EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), - EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), - EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), - EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), - EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), - EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), - EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), - EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), - EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), - EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), - EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), - EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), - EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), - EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), - EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), - EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), - EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), - EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), - EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), - EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), +static const char * const snd_emu1010_adc_pads[] = { + "ADC1 14dB PAD 0202 Capture Switch", + "ADC1 14dB PAD Audio Dock Capture Switch", + "ADC2 14dB PAD Audio Dock Capture Switch", + "ADC3 14dB PAD Audio Dock Capture Switch", }; - +static const unsigned short snd_emu1010_adc_pad_regs[] = { + EMU_HANA_0202_ADC_PAD1, + EMU_HANA_DOCK_ADC_PAD1, + EMU_HANA_DOCK_ADC_PAD2, + EMU_HANA_DOCK_ADC_PAD3, +}; #define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int mask = kcontrol->private_value & 0xff; + unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; + ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; return 0; } @@ -586,7 +768,7 @@ static int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int mask = kcontrol->private_value & 0xff; + unsigned int mask = snd_emu1010_adc_pad_regs[kcontrol->private_value]; unsigned int val, cache; val = ucontrol->value.integer.value[0]; cache = emu->emu1010.adc_pads; @@ -602,23 +784,29 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct return 0; } +static const struct snd_kcontrol_new emu1010_adc_pads_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_emu1010_adc_pads_info, + .get = snd_emu1010_adc_pads_get, + .put = snd_emu1010_adc_pads_put +}; -#define EMU1010_ADC_PADS(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_emu1010_adc_pads_info, \ - .get = snd_emu1010_adc_pads_get, \ - .put = snd_emu1010_adc_pads_put, \ - .private_value = chid \ -} +static const char * const snd_emu1010_dac_pads[] = { + "DAC1 0202 14dB PAD Playback Switch", + "DAC1 Audio Dock 14dB PAD Playback Switch", + "DAC2 Audio Dock 14dB PAD Playback Switch", + "DAC3 Audio Dock 14dB PAD Playback Switch", + "DAC4 Audio Dock 14dB PAD Playback Switch", +}; -static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = { - EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), - EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), - EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), - EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), +static const unsigned short snd_emu1010_dac_regs[] = { + EMU_HANA_0202_DAC_PAD1, + EMU_HANA_DOCK_DAC_PAD1, + EMU_HANA_DOCK_DAC_PAD2, + EMU_HANA_DOCK_DAC_PAD3, + EMU_HANA_DOCK_DAC_PAD4, }; #define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info @@ -626,7 +814,8 @@ static const struct snd_kcontrol_new snd_emu1010_adc_pads[] = { static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int mask = kcontrol->private_value & 0xff; + unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; + ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; return 0; } @@ -634,40 +823,68 @@ static int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ct static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - unsigned int mask = kcontrol->private_value & 0xff; + unsigned int mask = snd_emu1010_dac_regs[kcontrol->private_value]; unsigned int val, cache; + int change; + val = ucontrol->value.integer.value[0]; cache = emu->emu1010.dac_pads; if (val == 1) cache = cache | mask; else cache = cache & ~mask; - if (cache != emu->emu1010.dac_pads) { + change = (cache != emu->emu1010.dac_pads); + if (change) { snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); emu->emu1010.dac_pads = cache; } - return 0; + return change; } +static const struct snd_kcontrol_new emu1010_dac_pads_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_emu1010_dac_pads_info, + .get = snd_emu1010_dac_pads_get, + .put = snd_emu1010_dac_pads_put +}; -#define EMU1010_DAC_PADS(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .info = snd_emu1010_dac_pads_info, \ - .get = snd_emu1010_dac_pads_get, \ - .put = snd_emu1010_dac_pads_put, \ - .private_value = chid \ -} +struct snd_emu1010_pads_info { + const char * const *adc_ctls, * const *dac_ctls; + unsigned n_adc_ctls, n_dac_ctls; +}; -static const struct snd_kcontrol_new snd_emu1010_dac_pads[] = { - EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), - EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), - EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), - EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), - EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), +static const struct snd_emu1010_pads_info emu1010_pads_info[] = { + { + /* rev1 1010 */ + .adc_ctls = snd_emu1010_adc_pads, + .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads), + .dac_ctls = snd_emu1010_dac_pads, + .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads), + }, + { + /* rev2 1010 */ + .adc_ctls = snd_emu1010_adc_pads, + .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 1, + .dac_ctls = snd_emu1010_dac_pads, + .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 1, + }, + { + /* 1616(m) cardbus */ + .adc_ctls = snd_emu1010_adc_pads + 1, + .n_adc_ctls = ARRAY_SIZE(snd_emu1010_adc_pads) - 2, + .dac_ctls = snd_emu1010_dac_pads + 1, + .n_dac_ctls = ARRAY_SIZE(snd_emu1010_dac_pads) - 2, + }, + { + /* 0404 */ + .adc_ctls = NULL, + .n_adc_ctls = 0, + .dac_ctls = NULL, + .n_dac_ctls = 0, + }, }; @@ -1039,22 +1256,19 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, return change; } -#define I2C_VOLUME(xname,chid) \ -{ \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ - .info = snd_audigy_i2c_volume_info, \ - .get = snd_audigy_i2c_volume_get, \ - .put = snd_audigy_i2c_volume_put, \ - .tlv = { .p = snd_audigy_db_scale2 }, \ - .private_value = chid \ -} - +static const struct snd_kcontrol_new i2c_volume_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = snd_audigy_i2c_volume_info, + .get = snd_audigy_i2c_volume_get, + .put = snd_audigy_i2c_volume_put, + .tlv = { .p = snd_audigy_db_scale2 } +}; -static const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { - I2C_VOLUME("Mic Capture Volume", 0), - I2C_VOLUME("Line Capture Volume", 0) +static const char * const snd_audigy_i2c_volume_ctls[] = { + "Mic Capture Volume", + "Line Capture Volume", }; #if 0 @@ -1070,10 +1284,7 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int tmp; - unsigned long flags; - - spin_lock_irqsave(&emu->reg_lock, flags); tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); switch (tmp & A_SPDIF_RATE_MASK) { case A_SPDIF_44100: @@ -1088,7 +1299,6 @@ static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, default: ucontrol->value.enumerated.item[0] = 1; } - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -1146,7 +1356,6 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); int change; unsigned int val; - unsigned long flags; /* Limit: emu->spdif_bits */ if (idx >= 3) @@ -1155,13 +1364,11 @@ static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); - spin_lock_irqsave(&emu->reg_lock, flags); change = val != emu->spdif_bits[idx]; if (change) { snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; } - spin_unlock_irqrestore(&emu->reg_lock, flags); return change; } @@ -1189,10 +1396,10 @@ static const struct snd_kcontrol_new snd_emu10k1_spdif_control = static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) { if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXRT1, voice, - snd_emu10k1_compose_audigy_fxrt1(route)); - snd_emu10k1_ptr_write(emu, A_FXRT2, voice, - snd_emu10k1_compose_audigy_fxrt2(route)); + snd_emu10k1_ptr_write_multiple(emu, voice, + A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(route), + A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(route), + REGLIST_END); } else { snd_emu10k1_ptr_write(emu, FXRT, voice, snd_emu10k1_compose_send_routing(route)); @@ -1206,11 +1413,8 @@ static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsig snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); if (emu->audigy) { - unsigned int val = ((unsigned int)volume[4] << 24) | - ((unsigned int)volume[5] << 16) | - ((unsigned int)volume[6] << 8) | - (unsigned int)volume[7]; - snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); + snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, + snd_emu10k1_compose_audigy_sendamounts(volume)); } } @@ -1229,7 +1433,6 @@ static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct s static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; @@ -1237,12 +1440,10 @@ static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); for (voice = 0; voice < 3; voice++) for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[(voice * num_efx) + idx] = mix->send_routing[voice][idx] & mask; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -1266,13 +1467,13 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, change = 1; } } - if (change && mix->epcm) { - if (mix->epcm->voices[0] && mix->epcm->voices[1]) { + if (change && mix->epcm && mix->epcm->voices[0]) { + if (!mix->epcm->voices[0]->last) { update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, &mix->send_routing[1][0]); - update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, + update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number + 1, &mix->send_routing[2][0]); - } else if (mix->epcm->voices[0]) { + } else { update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, &mix->send_routing[0][0]); } @@ -1305,17 +1506,14 @@ static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct sn static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int idx; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < 3*num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -1337,13 +1535,13 @@ static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, change = 1; } } - if (change && mix->epcm) { - if (mix->epcm->voices[0] && mix->epcm->voices[1]) { + if (change && mix->epcm && mix->epcm->voices[0]) { + if (!mix->epcm->voices[0]->last) { update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, &mix->send_volume[1][0]); - update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, + update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number + 1, &mix->send_volume[2][0]); - } else if (mix->epcm->voices[0]) { + } else { update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, &mix->send_volume[0][0]); } @@ -1368,7 +1566,7 @@ static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_e uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 3; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 0xffff; + uinfo->value.integer.max = 0x1fffd; return 0; } @@ -1378,13 +1576,10 @@ static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; - unsigned long flags; int idx; - spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < 3; idx++) - ucontrol->value.integer.value[idx] = mix->attn[idx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); + ucontrol->value.integer.value[idx] = mix->attn[idx] * 0xffffU / 0x8000U; return 0; } @@ -1399,17 +1594,18 @@ static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < 3; idx++) { - val = ucontrol->value.integer.value[idx] & 0xffff; + unsigned uval = ucontrol->value.integer.value[idx] & 0x1ffff; + val = uval * 0x8000U / 0xffffU; if (mix->attn[idx] != val) { mix->attn[idx] = val; change = 1; } } - if (change && mix->epcm) { - if (mix->epcm->voices[0] && mix->epcm->voices[1]) { + if (change && mix->epcm && mix->epcm->voices[0]) { + if (!mix->epcm->voices[0]->last) { snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); - snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); - } else if (mix->epcm->voices[0]) { + snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number + 1, mix->attn[2]); + } else { snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); } } @@ -1443,7 +1639,6 @@ static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, stru static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; @@ -1451,11 +1646,9 @@ static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_routing[0][idx] & mask; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -1513,17 +1706,14 @@ static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struc static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; int idx; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); for (idx = 0; idx < num_efx; idx++) ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } @@ -1572,7 +1762,7 @@ static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_c uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 0xffff; + uinfo->value.integer.max = 0x1fffd; return 0; } @@ -1582,11 +1772,8 @@ static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; - unsigned long flags; - spin_lock_irqsave(&emu->reg_lock, flags); - ucontrol->value.integer.value[0] = mix->attn[0]; - spin_unlock_irqrestore(&emu->reg_lock, flags); + ucontrol->value.integer.value[0] = mix->attn[0] * 0xffffU / 0x8000U; return 0; } @@ -1598,9 +1785,11 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; int change = 0, val; + unsigned uval; spin_lock_irqsave(&emu->reg_lock, flags); - val = ucontrol->value.integer.value[0] & 0xffff; + uval = ucontrol->value.integer.value[0] & 0x1ffff; + val = uval * 0x8000U / 0xffffU; if (mix->attn[0] != val) { mix->attn[0] = val; change = 1; @@ -1654,7 +1843,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, sw = ucontrol->value.integer.value[0]; if (emu->card_capabilities->invert_shared_spdif) sw = !sw; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irqsave(&emu->emu_lock, flags); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { @@ -1675,7 +1864,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, reg |= val; outl(reg | val, emu->port + HCFG); } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irqrestore(&emu->emu_lock, flags); return change; } @@ -1777,7 +1966,7 @@ static int rename_ctl(struct snd_card *card, const char *src, const char *dst) int snd_emu10k1_mixer(struct snd_emu10k1 *emu, int pcm_device, int multi_device) { - int err, pcm; + int err; struct snd_kcontrol *kctl; struct snd_card *card = emu->card; const char * const *c; @@ -2041,49 +2230,7 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, if (err) return err; - /* initialize the routing and volume table for each pcm playback stream */ - for (pcm = 0; pcm < 32; pcm++) { - struct snd_emu10k1_pcm_mixer *mix; - int v; - - mix = &emu->pcm_mixer[pcm]; - mix->epcm = NULL; - - for (v = 0; v < 4; v++) - mix->send_routing[0][v] = - mix->send_routing[1][v] = - mix->send_routing[2][v] = v; - - memset(&mix->send_volume, 0, sizeof(mix->send_volume)); - mix->send_volume[0][0] = mix->send_volume[0][1] = - mix->send_volume[1][0] = mix->send_volume[2][1] = 255; - - mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; - } - - /* initialize the routing and volume table for the multichannel playback stream */ - for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { - struct snd_emu10k1_pcm_mixer *mix; - int v; - - mix = &emu->efx_pcm_mixer[pcm]; - mix->epcm = NULL; - - mix->send_routing[0][0] = pcm; - mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; - for (v = 0; v < 2; v++) - mix->send_routing[0][2+v] = 13+v; - if (emu->audigy) - for (v = 0; v < 4; v++) - mix->send_routing[0][4+v] = 60+v; - - memset(&mix->send_volume, 0, sizeof(mix->send_volume)); - mix->send_volume[0][0] = 255; - - mix->attn[0] = 0xffff; - } - - if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ + if (!emu->card_capabilities->ecard && !emu->card_capabilities->emu_model) { /* sb live! and audigy */ kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); if (!kctl) @@ -2135,105 +2282,60 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, return err; } - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - /* 1616(m) cardbus */ - int i; + if (emu->card_capabilities->emu_model) { + unsigned i, emu_idx = emu1010_idx(emu); + const struct snd_emu1010_routing_info *emu_ri = + &emu1010_routing_info[emu_idx]; + const struct snd_emu1010_pads_info *emu_pi = &emu1010_pads_info[emu_idx]; + + for (i = 0; i < emu_ri->n_ins; i++) + emu->emu1010.input_source[i] = + emu1010_map_source(emu_ri, emu_ri->in_dflts[i]); + for (i = 0; i < emu_ri->n_outs; i++) + emu->emu1010.output_source[i] = + emu1010_map_source(emu_ri, emu_ri->out_dflts[i]); + snd_emu1010_apply_sources(emu); - for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], - emu)); - if (err < 0) - return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], - emu)); - if (err < 0) - return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); - if (err < 0) - return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); - if (err < 0) - return err; - } err = snd_ctl_add(card, snd_ctl_new1(&snd_emu1010_internal_clock, emu)); if (err < 0) return err; - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_out, emu)); + + err = add_ctls(emu, &emu1010_adc_pads_ctl, + emu_pi->adc_ctls, emu_pi->n_adc_ctls); if (err < 0) return err; - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_in, emu)); + err = add_ctls(emu, &emu1010_dac_pads_ctl, + emu_pi->dac_ctls, emu_pi->n_dac_ctls); if (err < 0) return err; - } else if (emu->card_capabilities->emu_model) { - /* all other e-mu cards for now */ - int i; - - for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], - emu)); - if (err < 0) - return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], - emu)); - if (err < 0) - return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { + if (!emu->card_capabilities->no_adat) { err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); + snd_ctl_new1(&snd_emu1010_optical_out, emu)); if (err < 0) return err; - } - for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); + snd_ctl_new1(&snd_emu1010_optical_in, emu)); if (err < 0) return err; } - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_internal_clock, emu)); - if (err < 0) - return err; - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_out, emu)); - if (err < 0) - return err; - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_in, emu)); + + err = add_emu1010_source_mixers(emu); if (err < 0) return err; } if ( emu->card_capabilities->i2c_adc) { - int i; - err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); if (err < 0) return err; - for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); - if (err < 0) - return err; - } + err = add_ctls(emu, &i2c_volume_ctl, + snd_audigy_i2c_volume_ctls, + ARRAY_SIZE(snd_audigy_i2c_volume_ctls)); + if (err < 0) + return err; } if (emu->card_capabilities->ac97_chip && emu->audigy) { diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index e8d2f0f6fbb3..550caefa0ce4 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -76,65 +76,64 @@ static void snd_emu10k1_pcm_efx_interrupt(struct snd_emu10k1 *emu, snd_pcm_period_elapsed(emu->pcm_capture_efx_substream); } -static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voices) +static void snd_emu10k1_pcm_free_voices(struct snd_emu10k1_pcm *epcm) { - int err, i; - - if (epcm->voices[1] != NULL && voices < 2) { - snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); - epcm->voices[1] = NULL; - } - for (i = 0; i < voices; i++) { - if (epcm->voices[i] == NULL) - break; - } - if (i == voices) - return 0; /* already allocated */ - - for (i = 0; i < ARRAY_SIZE(epcm->voices); i++) { + for (unsigned i = 0; i < ARRAY_SIZE(epcm->voices); i++) { if (epcm->voices[i]) { snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); epcm->voices[i] = NULL; } } +} + +static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm *epcm, + int type, int count, int channels) +{ + int err; + + snd_emu10k1_pcm_free_voices(epcm); + err = snd_emu10k1_voice_alloc(epcm->emu, - epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, - voices, - &epcm->voices[0]); - + type, count, channels, + epcm, &epcm->voices[0]); if (err < 0) return err; - epcm->voices[0]->epcm = epcm; - if (voices > 1) { - for (i = 1; i < voices; i++) { - epcm->voices[i] = &epcm->emu->voices[(epcm->voices[0]->number + i) % NUM_G]; - epcm->voices[i]->epcm = epcm; - } - } + if (epcm->extra == NULL) { + // The hardware supports only (half-)loop interrupts, so to support an + // arbitrary number of periods per buffer, we use an extra voice with a + // period-sized loop as the interrupt source. Additionally, the interrupt + // timing of the hardware is "suboptimal" and needs some compensation. err = snd_emu10k1_voice_alloc(epcm->emu, - epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, - 1, - &epcm->extra); + type + 1, 1, 1, + epcm, &epcm->extra); if (err < 0) { /* dev_dbg(emu->card->dev, "pcm_channel_alloc: " "failed extra: voices=%d, frame=%d\n", voices, frame); */ - for (i = 0; i < voices; i++) { - snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); - epcm->voices[i] = NULL; - } + snd_emu10k1_pcm_free_voices(epcm); return err; } - epcm->extra->epcm = epcm; epcm->extra->interrupt = snd_emu10k1_pcm_interrupt; } + return 0; } -static const unsigned int capture_period_sizes[31] = { +// Primes 2-7 and 2^n multiples thereof, up to 16. +static const unsigned int efx_capture_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16 +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_efx_capture_channels = { + .count = ARRAY_SIZE(efx_capture_channels), + .list = efx_capture_channels, + .mask = 0 +}; + +static const unsigned int capture_buffer_sizes[31] = { 384, 448, 512, 640, 384*2, 448*2, 512*2, 640*2, 384*4, 448*4, 512*4, 640*4, @@ -145,9 +144,9 @@ static const unsigned int capture_period_sizes[31] = { 384*128,448*128,512*128 }; -static const struct snd_pcm_hw_constraint_list hw_constraints_capture_period_sizes = { +static const struct snd_pcm_hw_constraint_list hw_constraints_capture_buffer_sizes = { .count = 31, - .list = capture_period_sizes, + .list = capture_buffer_sizes, .mask = 0 }; @@ -232,147 +231,116 @@ static unsigned int emu10k1_select_interprom(unsigned int pitch_target) return CCCA_INTERPROM_2; } -/* - * calculate cache invalidate size - * - * stereo: channel is stereo - * w_16: using 16bit samples - * - * returns: cache invalidate size in samples - */ -static inline int emu10k1_ccis(int stereo, int w_16) +static u16 emu10k1_send_target_from_amount(u8 amount) { - if (w_16) { - return stereo ? 24 : 26; - } else { - return stereo ? 24*2 : 26*2; - } + static const u8 shifts[8] = { 4, 4, 5, 6, 7, 8, 9, 10 }; + static const u16 offsets[8] = { 0, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 }; + u8 exp; + + if (amount == 0xff) + return 0xffff; + exp = amount >> 5; + return ((amount & 0x1f) << shifts[exp]) + offsets[exp]; } static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu, - int master, int extra, struct snd_emu10k1_voice *evoice, + bool w_16, bool stereo, unsigned int start_addr, unsigned int end_addr, - struct snd_emu10k1_pcm_mixer *mix) + const unsigned char *send_routing, + const unsigned char *send_amount) { struct snd_pcm_substream *substream = evoice->epcm->substream; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int silent_page, tmp; - int voice, stereo, w_16; - unsigned char send_amount[8]; - unsigned char send_routing[8]; - unsigned long flags; + unsigned int silent_page; + int voice; unsigned int pitch_target; - unsigned int ccis; voice = evoice->number; - stereo = runtime->channels == 2; - w_16 = snd_pcm_format_width(runtime->format) == 16; - if (!extra && stereo) { - start_addr >>= 1; - end_addr >>= 1; - } - if (w_16) { - start_addr >>= 1; - end_addr >>= 1; - } - - spin_lock_irqsave(&emu->reg_lock, flags); - - /* volume parameters */ - if (extra) { - memset(send_routing, 0, sizeof(send_routing)); - send_routing[0] = 0; - send_routing[1] = 1; - send_routing[2] = 2; - send_routing[3] = 3; - memset(send_amount, 0, sizeof(send_amount)); + if (emu->card_capabilities->emu_model) + pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ + else + pitch_target = emu10k1_calc_pitch_target(runtime->rate); + silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | + (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); + snd_emu10k1_ptr_write_multiple(emu, voice, + // Not really necessary for the slave, but it doesn't hurt + CPF, stereo ? CPF_STEREO_MASK : 0, + // Assumption that PT is already 0 so no harm overwriting + PTRX, (send_amount[0] << 8) | send_amount[1], + // Stereo slaves don't need to have the addresses set, but it doesn't hurt + DSL, end_addr | (send_amount[3] << 24), + PSST, start_addr | (send_amount[2] << 24), + CCCA, emu10k1_select_interprom(pitch_target) | + (w_16 ? 0 : CCCA_8BITSELECT), + // Clear filter delay memory + Z1, 0, + Z2, 0, + // Invalidate maps + MAPA, silent_page, + MAPB, silent_page, + // Disable filter (in conjunction with CCCA_RESONANCE == 0) + VTFT, VTFT_FILTERTARGET_MASK, + CVCF, CVCF_CURRENTFILTER_MASK, + REGLIST_END); + // Setup routing + if (emu->audigy) { + snd_emu10k1_ptr_write_multiple(emu, voice, + A_FXRT1, snd_emu10k1_compose_audigy_fxrt1(send_routing), + A_FXRT2, snd_emu10k1_compose_audigy_fxrt2(send_routing), + A_SENDAMOUNTS, snd_emu10k1_compose_audigy_sendamounts(send_amount), + REGLIST_END); + for (int i = 0; i < 4; i++) { + u32 aml = emu10k1_send_target_from_amount(send_amount[2 * i]); + u32 amh = emu10k1_send_target_from_amount(send_amount[2 * i + 1]); + snd_emu10k1_ptr_write(emu, A_CSBA + i, voice, (amh << 16) | aml); + } } else { - /* mono, left, right (master voice = left) */ - tmp = stereo ? (master ? 1 : 2) : 0; - memcpy(send_routing, &mix->send_routing[tmp][0], 8); - memcpy(send_amount, &mix->send_volume[tmp][0], 8); + snd_emu10k1_ptr_write(emu, FXRT, voice, + snd_emu10k1_compose_send_routing(send_routing)); } - ccis = emu10k1_ccis(stereo, w_16); - - if (master) { - evoice->epcm->ccca_start_addr = start_addr + ccis; - if (extra) { - start_addr += ccis; - end_addr += ccis + emu->delay_pcm_irq; - } - if (stereo && !extra) { - snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); - snd_emu10k1_ptr_write(emu, CPF, (voice + 1), CPF_STEREO_MASK); - } else { - snd_emu10k1_ptr_write(emu, CPF, voice, 0); - } - } + emu->voices[voice].dirty = 1; +} - /* setup routing */ - if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXRT1, voice, - snd_emu10k1_compose_audigy_fxrt1(send_routing)); - snd_emu10k1_ptr_write(emu, A_FXRT2, voice, - snd_emu10k1_compose_audigy_fxrt2(send_routing)); - snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, - ((unsigned int)send_amount[4] << 24) | - ((unsigned int)send_amount[5] << 16) | - ((unsigned int)send_amount[6] << 8) | - (unsigned int)send_amount[7]); - } else - snd_emu10k1_ptr_write(emu, FXRT, voice, - snd_emu10k1_compose_send_routing(send_routing)); - /* Assumption that PT is already 0 so no harm overwriting */ - snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); - snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); - snd_emu10k1_ptr_write(emu, PSST, voice, - (start_addr + (extra ? emu->delay_pcm_irq : 0)) | - (send_amount[2] << 24)); - if (emu->card_capabilities->emu_model) - pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ - else - pitch_target = emu10k1_calc_pitch_target(runtime->rate); - if (extra) - snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | - emu10k1_select_interprom(pitch_target) | - (w_16 ? 0 : CCCA_8BITSELECT)); - else - snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | - emu10k1_select_interprom(pitch_target) | - (w_16 ? 0 : CCCA_8BITSELECT)); - /* Clear filter delay memory */ - snd_emu10k1_ptr_write(emu, Z1, voice, 0); - snd_emu10k1_ptr_write(emu, Z2, voice, 0); - /* invalidate maps */ - silent_page = ((unsigned int)emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); - snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); - snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); - /* modulation envelope */ - snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK); - snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK); - snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); - snd_emu10k1_ptr_write(emu, DCYSUSM, voice, 0x007f); - snd_emu10k1_ptr_write(emu, LFOVAL1, voice, 0x8000); - snd_emu10k1_ptr_write(emu, LFOVAL2, voice, 0x8000); - snd_emu10k1_ptr_write(emu, FMMOD, voice, 0); - snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); - snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); - snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); - /* volume envelope */ - snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); - snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); - /* filter envelope */ - snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); - /* pitch envelope */ - snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); +static void snd_emu10k1_pcm_init_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + bool w_16, bool stereo, + unsigned int start_addr, + unsigned int end_addr, + struct snd_emu10k1_pcm_mixer *mix) +{ + unsigned long flags; + spin_lock_irqsave(&emu->reg_lock, flags); + snd_emu10k1_pcm_init_voice(emu, evoice, w_16, stereo, + start_addr, end_addr, + &mix->send_routing[stereo][0], + &mix->send_volume[stereo][0]); + if (stereo) + snd_emu10k1_pcm_init_voice(emu, evoice + 1, w_16, true, + start_addr, end_addr, + &mix->send_routing[2][0], + &mix->send_volume[2][0]); spin_unlock_irqrestore(&emu->reg_lock, flags); } +static void snd_emu10k1_pcm_init_extra_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + bool w_16, + unsigned int start_addr, + unsigned int end_addr) +{ + static const unsigned char send_routing[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + static const unsigned char send_amount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + snd_emu10k1_pcm_init_voice(emu, evoice, w_16, false, + start_addr, end_addr, + send_routing, send_amount); +} + static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { @@ -380,9 +348,19 @@ static int snd_emu10k1_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; size_t alloc_size; + int type, channels, count; int err; - err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params)); + if (epcm->type == PLAYBACK_EMUVOICE) { + type = EMU10K1_PCM; + channels = 1; + count = params_channels(hw_params); + } else { + type = EMU10K1_EFX; + channels = params_channels(hw_params); + count = 1; + } + err = snd_emu10k1_pcm_channel_alloc(epcm, type, count, channels); if (err < 0) return err; @@ -415,7 +393,6 @@ static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm; - int i; if (runtime->private_data == NULL) return 0; @@ -424,12 +401,7 @@ static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream) snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; } - for (i = 0; i < NUM_EFX_PLAYBACK; i++) { - if (epcm->voices[i]) { - snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); - epcm->voices[i] = NULL; - } - } + snd_emu10k1_pcm_free_voices(epcm); if (epcm->memblk) { snd_emu10k1_free_pages(emu, epcm->memblk); epcm->memblk = NULL; @@ -444,26 +416,21 @@ static int snd_emu10k1_playback_prepare(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; + bool w_16 = snd_pcm_format_width(runtime->format) == 16; + bool stereo = runtime->channels == 2; unsigned int start_addr, end_addr; - start_addr = epcm->start_addr; - end_addr = snd_pcm_lib_period_bytes(substream); - if (runtime->channels == 2) { - start_addr >>= 1; - end_addr >>= 1; - } - end_addr += start_addr; - snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, - start_addr, end_addr, NULL); - start_addr = epcm->start_addr; - end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); - snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], - start_addr, end_addr, - &emu->pcm_mixer[substream->number]); - if (epcm->voices[1]) - snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1], - start_addr, end_addr, - &emu->pcm_mixer[substream->number]); + start_addr = epcm->start_addr >> w_16; + end_addr = start_addr + runtime->period_size; + snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, w_16, + start_addr, end_addr); + start_addr >>= stereo; + epcm->ccca_start_addr = start_addr; + end_addr = start_addr + runtime->buffer_size; + snd_emu10k1_pcm_init_voices(emu, epcm->voices[0], w_16, stereo, + start_addr, end_addr, + &emu->pcm_mixer[substream->number]); + return 0; } @@ -472,28 +439,23 @@ static int snd_emu10k1_efx_playback_prepare(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; - unsigned int start_addr, end_addr; - unsigned int channel_size; - int i; - - start_addr = epcm->start_addr; - end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); + unsigned int start_addr; + unsigned int extra_size, channel_size; + unsigned int i; - channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK; + start_addr = epcm->start_addr >> 1; // 16-bit voices - snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, - start_addr, start_addr + (channel_size / 2), NULL); + extra_size = runtime->period_size; + channel_size = runtime->buffer_size; - /* only difference with the master voice is we use it for the pointer */ - snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], - start_addr, start_addr + channel_size, - &emu->efx_pcm_mixer[0]); + snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true, + start_addr, start_addr + extra_size); - start_addr += channel_size; - for (i = 1; i < NUM_EFX_PLAYBACK; i++) { - snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i], - start_addr, start_addr + channel_size, - &emu->efx_pcm_mixer[i]); + epcm->ccca_start_addr = start_addr; + for (i = 0; i < runtime->channels; i++) { + snd_emu10k1_pcm_init_voices(emu, epcm->voices[i], true, false, + start_addr, start_addr + channel_size, + &emu->efx_pcm_mixer[i]); start_addr += channel_size; } @@ -510,13 +472,12 @@ static const struct snd_pcm_hardware snd_emu10k1_efx_playback = .rates = SNDRV_PCM_RATE_48000, .rate_min = 48000, .rate_max = 48000, - .channels_min = NUM_EFX_PLAYBACK, + .channels_min = 1, .channels_max = NUM_EFX_PLAYBACK, - .buffer_bytes_max = (64*1024), - .period_bytes_min = 64, - .period_bytes_max = (64*1024), + .buffer_bytes_max = (128*1024), + .period_bytes_max = (128*1024), .periods_min = 2, - .periods_max = 2, + .periods_max = 1024, .fifo_size = 0, }; @@ -534,9 +495,17 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); break; case CAPTURE_EFX: + if (emu->card_capabilities->emu_model) { + // The upper 32 16-bit capture voices, two for each of the 16 32-bit channels. + // The lower voices are occupied by A_EXTOUT_*_CAP*. + epcm->capture_cr_val = 0; + epcm->capture_cr_val2 = 0xffffffff >> (32 - runtime->channels * 2); + } if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); - snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); + snd_emu10k1_ptr_write_multiple(emu, 0, + A_FXWC1, 0, + A_FXWC2, 0, + REGLIST_END); } else snd_emu10k1_ptr_write(emu, FXWC, 0, 0); break; @@ -547,7 +516,7 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream); epcm->capture_bs_val = 0; for (idx = 0; idx < 31; idx++) { - if (capture_period_sizes[idx] == epcm->capture_bufsize) { + if (capture_buffer_sizes[idx] == epcm->capture_bufsize) { epcm->capture_bs_val = idx + 1; break; } @@ -567,122 +536,176 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) return 0; } -static void snd_emu10k1_playback_invalidate_cache(struct snd_emu10k1 *emu, int extra, struct snd_emu10k1_voice *evoice) +static void snd_emu10k1_playback_fill_cache(struct snd_emu10k1 *emu, + unsigned voice, + u32 sample, bool stereo) { - struct snd_pcm_runtime *runtime; - unsigned int voice, stereo, i, ccis, cra = 64, cs, sample; + u32 ccr; - if (evoice == NULL) - return; - runtime = evoice->epcm->substream->runtime; - voice = evoice->number; - stereo = (!extra && runtime->channels == 2); - sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; - ccis = emu10k1_ccis(stereo, sample == 0); - /* set cs to 2 * number of cache registers beside the invalidated */ - cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; - if (cs > 16) cs = 16; - for (i = 0; i < cs; i++) { + // We assume that the cache is resting at this point (i.e., + // CCR_CACHEINVALIDSIZE is very small). + + // Clear leading frames. For simplicitly, this does too much, + // except for 16-bit stereo. And the interpolator will actually + // access them at all only when we're pitch-shifting. + for (int i = 0; i < 3; i++) snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample); - if (stereo) { - snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); - } - } - /* reset cache */ - snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); - snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); + + // Fill cache + ccr = (64 - 3) << REG_SHIFT(CCR_CACHEINVALIDSIZE); if (stereo) { - snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); - snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); + // The engine goes haywire if CCR_READADDRESS is out of sync + snd_emu10k1_ptr_write(emu, CCR, voice + 1, ccr); } - /* fill cache */ - snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); - if (stereo) { - snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); + snd_emu10k1_ptr_write(emu, CCR, voice, ccr); +} + +static void snd_emu10k1_playback_prepare_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + bool w_16, bool stereo, + int channels) +{ + struct snd_pcm_substream *substream = epcm->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned eloop_start = epcm->start_addr >> w_16; + unsigned loop_start = eloop_start >> stereo; + unsigned eloop_size = runtime->period_size; + unsigned loop_size = runtime->buffer_size; + u32 sample = w_16 ? 0 : 0x80808080; + + // To make the playback actually start at the 1st frame, + // we need to compensate for two circumstances: + // - The actual position is delayed by the cache size (64 frames) + // - The interpolator is centered around the 4th frame + loop_start += (epcm->resume_pos + 64 - 3) % loop_size; + for (int i = 0; i < channels; i++) { + unsigned voice = epcm->voices[i]->number; + snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, voice, loop_start); + loop_start += loop_size; + snd_emu10k1_playback_fill_cache(emu, voice, sample, stereo); } + + // The interrupt is triggered when CCCA_CURRADDR (CA) wraps around, + // which is ahead of the actual playback position, so the interrupt + // source needs to be delayed. + // + // In principle, this wouldn't need to be the cache's entire size - in + // practice, CCR_CACHEINVALIDSIZE (CIS) > `fetch threshold` has never + // been observed, and assuming 40 _bytes_ should be safe. + // + // The cache fills are somewhat random, which makes it impossible to + // align them with the interrupts. This makes a non-delayed interrupt + // source not practical, as the interrupt handler would have to wait + // for (CA - CIS) >= period_boundary for every channel in the stream. + // + // This is why all other (open) drivers for these chips use timer-based + // interrupts. + // + eloop_start += (epcm->resume_pos + eloop_size - 3) % eloop_size; + snd_emu10k1_ptr_write(emu, CCCA_CURRADDR, epcm->extra->number, eloop_start); + + // It takes a moment until the cache fills complete, + // but the unmuting takes long enough for that. } -static void snd_emu10k1_playback_prepare_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, - int master, int extra, - struct snd_emu10k1_pcm_mixer *mix) +static void snd_emu10k1_playback_commit_volume(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + unsigned int vattn) { - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - unsigned int attn, vattn; - unsigned int voice, tmp; + snd_emu10k1_ptr_write_multiple(emu, evoice->number, + VTFT, vattn | VTFT_FILTERTARGET_MASK, + CVCF, vattn | CVCF_CURRENTFILTER_MASK, + REGLIST_END); +} - if (evoice == NULL) /* skip second voice for mono */ - return; - substream = evoice->epcm->substream; - runtime = substream->runtime; - voice = evoice->number; +static void snd_emu10k1_playback_unmute_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + bool stereo, bool master, + struct snd_emu10k1_pcm_mixer *mix) +{ + unsigned int vattn; + unsigned int tmp; - attn = extra ? 0 : 0x00ff; - tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0; - vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0; - snd_emu10k1_ptr_write(emu, IFATN, voice, attn); - snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | VTFT_FILTERTARGET_MASK); - snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | CVCF_CURRENTFILTER_MASK); - snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f); - snd_emu10k1_voice_clear_loop_stop(emu, voice); + tmp = stereo ? (master ? 1 : 2) : 0; + vattn = mix->attn[tmp] << 16; + snd_emu10k1_playback_commit_volume(emu, evoice, vattn); } -static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice, int master, int extra) +static void snd_emu10k1_playback_unmute_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + bool stereo, + struct snd_emu10k1_pcm_mixer *mix) +{ + snd_emu10k1_playback_unmute_voice(emu, evoice, stereo, true, mix); + if (stereo) + snd_emu10k1_playback_unmute_voice(emu, evoice + 1, true, false, mix); +} + +static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) +{ + snd_emu10k1_playback_commit_volume(emu, evoice, 0); +} + +static void snd_emu10k1_playback_mute_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice, + bool stereo) +{ + snd_emu10k1_playback_mute_voice(emu, evoice); + if (stereo) + snd_emu10k1_playback_mute_voice(emu, evoice + 1); +} + +static void snd_emu10k1_playback_commit_pitch(struct snd_emu10k1 *emu, + u32 voice, u32 pitch_target) +{ + u32 ptrx = snd_emu10k1_ptr_read(emu, PTRX, voice); + u32 cpf = snd_emu10k1_ptr_read(emu, CPF, voice); + snd_emu10k1_ptr_write_multiple(emu, voice, + PTRX, (ptrx & ~PTRX_PITCHTARGET_MASK) | pitch_target, + CPF, (cpf & ~(CPF_CURRENTPITCH_MASK | CPF_FRACADDRESS_MASK)) | pitch_target, + REGLIST_END); +} + +static void snd_emu10k1_playback_trigger_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) { struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - unsigned int voice, pitch, pitch_target; + unsigned int voice, pitch_target; - if (evoice == NULL) /* skip second voice for mono */ - return; substream = evoice->epcm->substream; runtime = substream->runtime; voice = evoice->number; - pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; if (emu->card_capabilities->emu_model) pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */ else pitch_target = emu10k1_calc_pitch_target(runtime->rate); - snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); - if (master || evoice->epcm->type == PLAYBACK_EFX) - snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); - snd_emu10k1_ptr_write(emu, IP, voice, pitch); - if (extra) - snd_emu10k1_voice_intr_enable(emu, voice); + snd_emu10k1_playback_commit_pitch(emu, voice, pitch_target << 16); } -static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice) +static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) { unsigned int voice; - if (evoice == NULL) - return; voice = evoice->number; - snd_emu10k1_voice_intr_disable(emu, voice); - snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0); - snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0); - snd_emu10k1_ptr_write(emu, IFATN, voice, 0xffff); - snd_emu10k1_ptr_write(emu, VTFT, voice, VTFT_FILTERTARGET_MASK); - snd_emu10k1_ptr_write(emu, CVCF, voice, CVCF_CURRENTFILTER_MASK); - snd_emu10k1_ptr_write(emu, IP, voice, 0); + snd_emu10k1_playback_commit_pitch(emu, voice, 0); } -static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu, - struct snd_emu10k1_pcm *epcm, - struct snd_pcm_substream *substream, - struct snd_pcm_runtime *runtime) +static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm) { - unsigned int ptr, period_pos; + epcm->running = 1; + snd_emu10k1_voice_intr_enable(emu, epcm->extra->number); +} - /* try to sychronize the current position for the interrupt - source voice */ - period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt; - period_pos %= runtime->period_size; - ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number); - ptr &= ~0x00ffffff; - ptr |= epcm->ccca_start_addr + period_pos; - snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr); +static void snd_emu10k1_playback_set_stopped(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm) +{ + snd_emu10k1_voice_intr_disable(emu, epcm->extra->number); + epcm->running = 0; } static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, @@ -692,6 +715,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; struct snd_emu10k1_pcm_mixer *mix; + bool w_16 = snd_pcm_format_width(runtime->format) == 16; + bool stereo = runtime->channels == 2; int result = 0; /* @@ -702,29 +727,23 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); /* do we need this? */ - snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]); + snd_emu10k1_playback_prepare_voices(emu, epcm, w_16, stereo, 1); fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) - snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime); mix = &emu->pcm_mixer[substream->number]; - snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); - snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); - snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); - epcm->running = 1; + snd_emu10k1_playback_unmute_voices(emu, epcm->voices[0], stereo, mix); + snd_emu10k1_playback_set_running(emu, epcm); + snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0]); + snd_emu10k1_playback_trigger_voice(emu, epcm->extra); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - epcm->running = 0; snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); - snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); snd_emu10k1_playback_stop_voice(emu, epcm->extra); + snd_emu10k1_playback_set_stopped(emu, epcm); + snd_emu10k1_playback_mute_voices(emu, epcm->voices[0], stereo); break; default: result = -EINVAL; @@ -759,8 +778,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, break; case CAPTURE_EFX: if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); - snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); + snd_emu10k1_ptr_write_multiple(emu, 0, + A_FXWC1, epcm->capture_cr_val, + A_FXWC2, epcm->capture_cr_val2, + REGLIST_END); dev_dbg(emu->card->dev, "cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, @@ -787,8 +808,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, break; case CAPTURE_EFX: if (emu->audigy) { - snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); - snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); + snd_emu10k1_ptr_write_multiple(emu, 0, + A_FXWC1, 0, + A_FXWC2, 0, + REGLIST_END); } else snd_emu10k1_ptr_write(emu, FXWC, 0, 0); break; @@ -808,24 +831,27 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; - unsigned int ptr; + int ptr; if (!epcm->running) return 0; + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; -#if 0 /* Perex's code */ - ptr += runtime->buffer_size; ptr -= epcm->ccca_start_addr; - ptr %= runtime->buffer_size; -#else /* EMU10K1 Open Source code from Creative */ - if (ptr < epcm->ccca_start_addr) - ptr += runtime->buffer_size - epcm->ccca_start_addr; - else { - ptr -= epcm->ccca_start_addr; - if (ptr >= runtime->buffer_size) - ptr -= runtime->buffer_size; - } -#endif + + // This is the size of the whole cache minus the interpolator read-ahead, + // which leads us to the actual playback position. + // + // The cache is constantly kept mostly filled, so in principle we could + // return a more advanced position representing how far the hardware has + // already read the buffer, and set runtime->delay accordingly. However, + // this would be slightly different for every channel (and remarkably slow + // to obtain), so only a fixed worst-case value would be practical. + // + ptr -= 64 - 3; + if (ptr < 0) + ptr += runtime->buffer_size; + /* dev_dbg(emu->card->dev, "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", @@ -835,6 +861,49 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * return ptr; } +static u64 snd_emu10k1_efx_playback_voice_mask(struct snd_emu10k1_pcm *epcm, + int channels) +{ + u64 mask = 0; + + for (int i = 0; i < channels; i++) { + int voice = epcm->voices[i]->number; + mask |= 1ULL << voice; + } + return mask; +} + +static void snd_emu10k1_efx_playback_freeze_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + int channels) +{ + for (int i = 0; i < channels; i++) { + int voice = epcm->voices[i]->number; + snd_emu10k1_ptr_write(emu, CPF_STOP, voice, 1); + snd_emu10k1_playback_commit_pitch(emu, voice, PITCH_48000 << 16); + } +} + +static void snd_emu10k1_efx_playback_unmute_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + int channels) +{ + for (int i = 0; i < channels; i++) + snd_emu10k1_playback_unmute_voice(emu, epcm->voices[i], false, true, + &emu->efx_pcm_mixer[i]); +} + +static void snd_emu10k1_efx_playback_stop_voices(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm, + int channels) +{ + for (int i = 0; i < channels; i++) + snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]); + snd_emu10k1_playback_set_stopped(emu, epcm); + + for (int i = 0; i < channels; i++) + snd_emu10k1_playback_mute_voice(emu, epcm->voices[i]); +} static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, int cmd) @@ -842,45 +911,62 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream, struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; - int i; + u64 mask; int result = 0; spin_lock(&emu->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - /* prepare voices */ - for (i = 0; i < NUM_EFX_PLAYBACK; i++) { - snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); - } - snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); - fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); - snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0, - &emu->efx_pcm_mixer[0]); - for (i = 1; i < NUM_EFX_PLAYBACK; i++) - snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, 0, - &emu->efx_pcm_mixer[i]); - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0); - snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); - for (i = 1; i < NUM_EFX_PLAYBACK; i++) - snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); - epcm->running = 1; + mask = snd_emu10k1_efx_playback_voice_mask( + epcm, runtime->channels); + for (int i = 0; i < 10; i++) { + // Note that the freeze is not interruptible, so we make no + // effort to reset the bits outside the error handling here. + snd_emu10k1_voice_set_loop_stop_multiple(emu, mask); + snd_emu10k1_efx_playback_freeze_voices( + emu, epcm, runtime->channels); + snd_emu10k1_playback_prepare_voices( + emu, epcm, true, false, runtime->channels); + + // It might seem to make more sense to unmute the voices only after + // they have been started, to potentially avoid torturing the speakers + // if something goes wrong. However, we cannot unmute atomically, + // which means that we'd get some mild artifacts in the regular case. + snd_emu10k1_efx_playback_unmute_voices(emu, epcm, runtime->channels); + + snd_emu10k1_playback_set_running(emu, epcm); + result = snd_emu10k1_voice_clear_loop_stop_multiple_atomic(emu, mask); + if (result == 0) { + // The extra voice is allowed to lag a bit + snd_emu10k1_playback_trigger_voice(emu, epcm->extra); + goto leave; + } + + snd_emu10k1_efx_playback_stop_voices( + emu, epcm, runtime->channels); + + if (result != -EAGAIN) + break; + // The sync start can legitimately fail due to NMIs, etc. + } + snd_emu10k1_voice_clear_loop_stop_multiple(emu, mask); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - epcm->running = 0; - for (i = 0; i < NUM_EFX_PLAYBACK; i++) { - snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]); - } snd_emu10k1_playback_stop_voice(emu, epcm->extra); + snd_emu10k1_efx_playback_stop_voices( + emu, epcm, runtime->channels); + + epcm->resume_pos = snd_emu10k1_playback_pointer(substream); break; default: result = -EINVAL; break; } +leave: spin_unlock(&emu->reg_lock); return result; } @@ -920,9 +1006,8 @@ static const struct snd_pcm_hardware snd_emu10k1_playback = .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), - .period_bytes_min = 64, .period_bytes_max = (128*1024), - .periods_min = 1, + .periods_min = 2, .periods_max = 1024, .fifo_size = 0, }; @@ -938,7 +1023,7 @@ static const struct snd_pcm_hardware snd_emu10k1_capture = SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_8000_48000, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, .rate_max = 48000, .channels_min = 1, @@ -963,8 +1048,8 @@ static const struct snd_pcm_hardware snd_emu10k1_capture_efx = SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .rate_min = 44100, .rate_max = 192000, - .channels_min = 8, - .channels_max = 8, + .channels_min = 1, + .channels_max = 16, .buffer_bytes_max = (64*1024), .period_bytes_min = 384, .period_bytes_max = (64*1024), @@ -1025,13 +1110,29 @@ static int snd_emu10k1_efx_playback_close(struct snd_pcm_substream *substream) return 0; } +static int snd_emu10k1_playback_set_constraints(struct snd_pcm_runtime *runtime) +{ + int err; + + // The buffer size must be a multiple of the period size, to avoid a + // mismatch between the extra voice and the regular voices. + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + // The hardware is typically the cache's size of 64 frames ahead. + // Leave enough time for actually filling up the buffer. + err = snd_pcm_hw_constraint_minmax( + runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 128, UINT_MAX); + return err; +} + static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_emu10k1_pcm *epcm; struct snd_emu10k1_pcm_mixer *mix; struct snd_pcm_runtime *runtime = substream->runtime; - int i; + int i, j, err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -1043,13 +1144,19 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; - + err = snd_emu10k1_playback_set_constraints(runtime); + if (err < 0) { + kfree(epcm); + return err; + } + for (i = 0; i < NUM_EFX_PLAYBACK; i++) { mix = &emu->efx_pcm_mixer[i]; - mix->send_routing[0][0] = i; + for (j = 0; j < 8; j++) + mix->send_routing[0][j] = i + j; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); mix->send_volume[0][0] = 255; - mix->attn[0] = 0xffff; + mix->attn[0] = 0x8000; mix->epcm = epcm; snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1); } @@ -1073,12 +1180,7 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_playback; - err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (err < 0) { - kfree(epcm); - return err; - } - err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); + err = snd_emu10k1_playback_set_constraints(runtime); if (err < 0) { kfree(epcm); return err; @@ -1093,12 +1195,12 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) return err; } mix = &emu->pcm_mixer[substream->number]; - for (i = 0; i < 4; i++) + for (i = 0; i < 8; i++) mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; memset(&mix->send_volume, 0, sizeof(mix->send_volume)); mix->send_volume[0][0] = mix->send_volume[0][1] = mix->send_volume[1][0] = mix->send_volume[2][1] = 255; - mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; + mix->attn[0] = mix->attn[1] = mix->attn[2] = 0x8000; mix->epcm = epcm; snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1); return 0; @@ -1134,9 +1236,10 @@ static int snd_emu10k1_capture_open(struct snd_pcm_substream *substream) runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt; emu->pcm_capture_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates); return 0; } @@ -1172,10 +1275,10 @@ static int snd_emu10k1_capture_mic_open(struct snd_pcm_substream *substream) runtime->hw = snd_emu10k1_capture; runtime->hw.rates = SNDRV_PCM_RATE_8000; runtime->hw.rate_min = runtime->hw.rate_max = 8000; - runtime->hw.channels_min = 1; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt; emu->pcm_capture_mic_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); return 0; } @@ -1194,7 +1297,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int nefx = emu->audigy ? 64 : 32; - int idx; + int idx, err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -1212,7 +1315,6 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw = snd_emu10k1_capture_efx; runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; - spin_lock_irq(&emu->reg_lock); if (emu->card_capabilities->emu_model) { /* TODO * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | @@ -1220,8 +1322,6 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 * rate_min = 44100, * rate_max = 192000, - * channels_min = 16, - * channels_max = 16, * Need to add mixer control to fix sample rate * * There are 32 mono channels of 16bits each. @@ -1240,15 +1340,11 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) /* For 44.1kHz */ runtime->hw.rates = SNDRV_PCM_RATE_44100; runtime->hw.rate_min = runtime->hw.rate_max = 44100; - runtime->hw.channels_min = - runtime->hw.channels_max = 16; break; case 1: /* For 48kHz */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; - runtime->hw.channels_min = - runtime->hw.channels_max = 16; break; } #endif @@ -1265,10 +1361,8 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw.channels_min = runtime->hw.channels_max = 2; #endif runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; - /* efx_voices_mask[0] is expected to be zero - * efx_voices_mask[1] is expected to have 32bits set - */ } else { + spin_lock_irq(&emu->reg_lock); runtime->hw.channels_min = runtime->hw.channels_max = 0; for (idx = 0; idx < nefx; idx++) { if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { @@ -1276,13 +1370,20 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) runtime->hw.channels_max++; } } + epcm->capture_cr_val = emu->efx_voices_mask[0]; + epcm->capture_cr_val2 = emu->efx_voices_mask[1]; + spin_unlock_irq(&emu->reg_lock); } - epcm->capture_cr_val = emu->efx_voices_mask[0]; - epcm->capture_cr_val2 = emu->efx_voices_mask[1]; - spin_unlock_irq(&emu->reg_lock); + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &hw_constraints_efx_capture_channels); + if (err < 0) { + kfree(epcm); + return err; + } + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + &hw_constraints_capture_buffer_sizes); emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt; emu->pcm_capture_efx_substream = substream; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); return 0; } @@ -1433,10 +1534,8 @@ static int snd_emu10k1_pcm_efx_voices_mask_get(struct snd_kcontrol *kcontrol, st int nefx = emu->audigy ? 64 : 32; int idx; - spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < nefx; idx++) ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0; - spin_unlock_irq(&emu->reg_lock); return 0; } @@ -1445,7 +1544,6 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int nval[2], bits; int nefx = emu->audigy ? 64 : 32; - int nefxb = emu->audigy ? 7 : 6; int change, idx; nval[0] = nval[1] = 0; @@ -1455,12 +1553,7 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st bits++; } - // Check that the number of requested channels is a power of two - // not bigger than the number of available channels. - for (idx = 0; idx < nefxb; idx++) - if (1 << idx == bits) - break; - if (idx >= nefxb) + if (bits == 9 || bits == 11 || bits == 13 || bits == 15 || bits > 16) return -EINVAL; spin_lock_irq(&emu->reg_lock); @@ -1592,12 +1685,14 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); pcm->tram_shift = 0; - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size); - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */ - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size); - snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size); + snd_emu10k1_ptr_write_multiple(emu, 0, + emu->gpr_base + pcm->gpr_running, 0, /* reset */ + emu->gpr_base + pcm->gpr_trigger, 0, /* reset */ + emu->gpr_base + pcm->gpr_size, runtime->buffer_size, + emu->gpr_base + pcm->gpr_ptr, 0, /* reset ptr number */ + emu->gpr_base + pcm->gpr_count, runtime->period_size, + emu->gpr_base + pcm->gpr_tmpcount, runtime->period_size, + REGLIST_END); for (i = 0; i < pcm->channels; i++) snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels)); return 0; @@ -1745,37 +1840,29 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) strcpy(pcm->name, "Multichannel Capture/PT Playback"); emu->pcm_efx = pcm; - /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs - * to these - */ - - if (emu->audigy) { - emu->efx_voices_mask[0] = 0; - if (emu->card_capabilities->emu_model) - /* Pavel Hofman - 32 voices will be used for - * capture (write mode) - - * each bit = corresponding voice - */ - emu->efx_voices_mask[1] = 0xffffffff; - else + if (!emu->card_capabilities->emu_model) { + // On Sound Blasters, the DSP code copies the EXTINs to FXBUS2. + // The mask determines which of these and the EXTOUTs the multi- + // channel capture actually records (the channel order is fixed). + if (emu->audigy) { + emu->efx_voices_mask[0] = 0; emu->efx_voices_mask[1] = 0xffff; + } else { + emu->efx_voices_mask[0] = 0xffff0000; + emu->efx_voices_mask[1] = 0; + } + kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu); + if (!kctl) + return -ENOMEM; + kctl->id.device = device; + err = snd_ctl_add(emu->card, kctl); + if (err < 0) + return err; } else { - emu->efx_voices_mask[0] = 0xffff0000; - emu->efx_voices_mask[1] = 0; + // On E-MU cards, the DSP code copies the P16VINs/EMU32INs to + // FXBUS2. These are already selected & routed by the FPGA, + // so there is no need to apply additional masking. } - /* For emu1010, the control has to set 32 upper bits (voices) - * out of the 64 bits (voices) to true for the 16-channels capture - * to work correctly. Correct A_FXWC2 initial value (0xffffffff) - * is already defined but the snd_emu10k1_pcm_efx_voices_mask - * control can override this register's value. - */ - kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu); - if (!kctl) - return -ENOMEM; - kctl->id.device = device; - err = snd_ctl_add(emu->card, kctl); - if (err < 0) - return err; snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, &emu->pci->dev, 64*1024, 64*1024); diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bec72dc60a41..89ea3adff322 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -229,14 +229,16 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, u32 rate; if (emu->card_capabilities->emu_model) { - snd_emu1010_fpga_read(emu, 0x38, &value); - if ((value & 0x1) == 0) { - snd_emu1010_fpga_read(emu, 0x2a, &value); - snd_emu1010_fpga_read(emu, 0x2b, &value2); - rate = 0x1770000 / (((value << 5) | value2)+1); - snd_iprintf(buffer, "ADAT Locked : %u\n", rate); - } else { - snd_iprintf(buffer, "ADAT Unlocked\n"); + if (!emu->card_capabilities->no_adat) { + snd_emu1010_fpga_read(emu, 0x38, &value); + if ((value & 0x1) == 0) { + snd_emu1010_fpga_read(emu, 0x2a, &value); + snd_emu1010_fpga_read(emu, 0x2b, &value2); + rate = 0x1770000 / (((value << 5) | value2)+1); + snd_iprintf(buffer, "ADAT Locked : %u\n", rate); + } else { + snd_iprintf(buffer, "ADAT Unlocked\n"); + } } snd_emu1010_fpga_read(emu, 0x20, &value); if ((value & 0x4) == 0) { @@ -365,17 +367,19 @@ static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; struct snd_emu10k1_voice *voice; int idx; - - snd_iprintf(buffer, "ch\tuse\tpcm\tefx\tsynth\tmidi\n"); + static const char * const types[] = { + "Unused", "EFX", "EFX IRQ", "PCM", "PCM IRQ", "Synth" + }; + static_assert(ARRAY_SIZE(types) == EMU10K1_NUM_TYPES); + + snd_iprintf(buffer, "ch\tdirty\tlast\tuse\n"); for (idx = 0; idx < NUM_G; idx++) { voice = &emu->voices[idx]; - snd_iprintf(buffer, "%i\t%i\t%i\t%i\t%i\t%i\n", + snd_iprintf(buffer, "%i\t%u\t%u\t%s\n", idx, - voice->use, - voice->pcm, - voice->efx, - voice->synth, - voice->midi); + voice->dirty, + voice->last, + types[voice->use]); } } @@ -399,13 +403,10 @@ static void snd_emu_proc_io_reg_read(struct snd_info_entry *entry, { struct snd_emu10k1 *emu = entry->private_data; unsigned long value; - unsigned long flags; int i; snd_iprintf(buffer, "IO Registers:\n\n"); for(i = 0; i < 0x40; i+=4) { - spin_lock_irqsave(&emu->emu_lock, flags); value = inl(emu->port + i); - spin_unlock_irqrestore(&emu->emu_lock, flags); snd_iprintf(buffer, "%02X: %08lX\n", i, value); } } @@ -414,16 +415,13 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_emu10k1 *emu = entry->private_data; - unsigned long flags; char line[64]; u32 reg, val; while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; if (reg < 0x40 && val <= 0xffffffff) { - spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); - spin_unlock_irqrestore(&emu->emu_lock, flags); } } } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index cfb96a67aa35..9a839e7d283f 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -18,33 +18,42 @@ #include <linux/export.h> #include "p17v.h" +static inline bool check_ptr_reg(struct snd_emu10k1 *emu, unsigned int reg) +{ + if (snd_BUG_ON(!emu)) + return false; + if (snd_BUG_ON(reg & (emu->audigy ? (0xffff0000 & ~A_PTR_ADDRESS_MASK) + : (0xffff0000 & ~PTR_ADDRESS_MASK)))) + return false; + if (snd_BUG_ON(reg & 0x0000ffff & ~PTR_CHANNELNUM_MASK)) + return false; + return true; +} + unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { unsigned long flags; unsigned int regptr, val; unsigned int mask; - mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; - regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); + regptr = (reg << 16) | chn; + if (!check_ptr_reg(emu, regptr)) + return 0; + + spin_lock_irqsave(&emu->emu_lock, flags); + outl(regptr, emu->port + PTR); + val = inl(emu->port + DATA); + spin_unlock_irqrestore(&emu->emu_lock, flags); if (reg & 0xff000000) { unsigned char size, offset; size = (reg >> 24) & 0x3f; offset = (reg >> 16) & 0x1f; - mask = ((1 << size) - 1) << offset; - - spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + PTR); - val = inl(emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + mask = (1 << size) - 1; - return (val & mask) >> offset; + return (val >> offset) & mask; } else { - spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + PTR); - val = inl(emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); return val; } } @@ -57,34 +66,65 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i unsigned long flags; unsigned int mask; - if (snd_BUG_ON(!emu)) + regptr = (reg << 16) | chn; + if (!check_ptr_reg(emu, regptr)) return; - mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; - regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); if (reg & 0xff000000) { unsigned char size, offset; size = (reg >> 24) & 0x3f; offset = (reg >> 16) & 0x1f; - mask = ((1 << size) - 1) << offset; - data = (data << offset) & mask; + mask = (1 << size) - 1; + if (snd_BUG_ON(data & ~mask)) + return; + mask <<= offset; + data <<= offset; spin_lock_irqsave(&emu->emu_lock, flags); outl(regptr, emu->port + PTR); data |= inl(emu->port + DATA) & ~mask; - outl(data, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } else { spin_lock_irqsave(&emu->emu_lock, flags); outl(regptr, emu->port + PTR); - outl(data, emu->port + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); } + outl(data, emu->port + DATA); + spin_unlock_irqrestore(&emu->emu_lock, flags); } EXPORT_SYMBOL(snd_emu10k1_ptr_write); +void snd_emu10k1_ptr_write_multiple(struct snd_emu10k1 *emu, unsigned int chn, ...) +{ + va_list va; + u32 addr_mask; + unsigned long flags; + + if (snd_BUG_ON(!emu)) + return; + if (snd_BUG_ON(chn & ~PTR_CHANNELNUM_MASK)) + return; + addr_mask = ~((emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK) >> 16); + + va_start(va, chn); + spin_lock_irqsave(&emu->emu_lock, flags); + for (;;) { + u32 data; + u32 reg = va_arg(va, u32); + if (reg == REGLIST_END) + break; + data = va_arg(va, u32); + if (snd_BUG_ON(reg & addr_mask)) // Only raw registers supported here + continue; + outl((reg << 16) | chn, emu->port + PTR); + outl(data, emu->port + DATA); + } + spin_unlock_irqrestore(&emu->emu_lock, flags); + va_end(va); +} + +EXPORT_SYMBOL(snd_emu10k1_ptr_write_multiple); + unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) @@ -233,16 +273,13 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, return err; } -void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) +static void snd_emu1010_fpga_write_locked(struct snd_emu10k1 *emu, u32 reg, u32 value) { - unsigned long flags; - if (snd_BUG_ON(reg > 0x3f)) return; reg += 0x40; /* 0x40 upwards are registers. */ if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */ return; - spin_lock_irqsave(&emu->emu_lock, flags); outw(reg, emu->port + A_GPIO); udelay(10); outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ @@ -250,6 +287,14 @@ void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) outw(value, emu->port + A_GPIO); udelay(10); outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ +} + +void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_write_locked(emu, reg, value); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -276,14 +321,18 @@ void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) */ void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) { + unsigned long flags; + if (snd_BUG_ON(dst & ~0x71f)) return; if (snd_BUG_ON(src & ~0x71f)) return; - snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8); - snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f); - snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8); - snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f); + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTHI, dst >> 8); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_DESTLO, dst & 0x1f); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCHI, src >> 8); + snd_emu1010_fpga_write_locked(emu, EMU_HANA_SRCLO, src & 0x1f); + spin_unlock_irqrestore(&emu->emu_lock, flags); } void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) @@ -416,6 +465,7 @@ void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int spin_unlock_irqrestore(&emu->emu_lock, flags); } +#if 0 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum) { unsigned long flags; @@ -453,6 +503,89 @@ void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voi outl(sol, emu->port + DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); } +#endif + +void snd_emu10k1_voice_set_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) +{ + unsigned long flags; + + spin_lock_irqsave(&emu->emu_lock, flags); + outl(SOLEL << 16, emu->port + PTR); + outl(inl(emu->port + DATA) | (u32)voices, emu->port + DATA); + outl(SOLEH << 16, emu->port + PTR); + outl(inl(emu->port + DATA) | (u32)(voices >> 32), emu->port + DATA); + spin_unlock_irqrestore(&emu->emu_lock, flags); +} + +void snd_emu10k1_voice_clear_loop_stop_multiple(struct snd_emu10k1 *emu, u64 voices) +{ + unsigned long flags; + + spin_lock_irqsave(&emu->emu_lock, flags); + outl(SOLEL << 16, emu->port + PTR); + outl(inl(emu->port + DATA) & (u32)~voices, emu->port + DATA); + outl(SOLEH << 16, emu->port + PTR); + outl(inl(emu->port + DATA) & (u32)(~voices >> 32), emu->port + DATA); + spin_unlock_irqrestore(&emu->emu_lock, flags); +} + +int snd_emu10k1_voice_clear_loop_stop_multiple_atomic(struct snd_emu10k1 *emu, u64 voices) +{ + unsigned long flags; + u32 soll, solh; + int ret = -EIO; + + spin_lock_irqsave(&emu->emu_lock, flags); + + outl(SOLEL << 16, emu->port + PTR); + soll = inl(emu->port + DATA); + outl(SOLEH << 16, emu->port + PTR); + solh = inl(emu->port + DATA); + + soll &= (u32)~voices; + solh &= (u32)(~voices >> 32); + + for (int tries = 0; tries < 1000; tries++) { + const u32 quart = 1U << (REG_SIZE(WC_CURRENTCHANNEL) - 2); + // First we wait for the third quarter of the sample cycle ... + u32 wc = inl(emu->port + WC); + u32 cc = REG_VAL_GET(WC_CURRENTCHANNEL, wc); + if (cc >= quart * 2 && cc < quart * 3) { + // ... and release the low voices, while the high ones are serviced. + outl(SOLEL << 16, emu->port + PTR); + outl(soll, emu->port + DATA); + // Then we wait for the first quarter of the next sample cycle ... + for (; tries < 1000; tries++) { + cc = REG_VAL_GET(WC_CURRENTCHANNEL, inl(emu->port + WC)); + if (cc < quart) + goto good; + // We will block for 10+ us with interrupts disabled. This is + // not nice at all, but necessary for reasonable reliability. + udelay(1); + } + break; + good: + // ... and release the high voices, while the low ones are serviced. + outl(SOLEH << 16, emu->port + PTR); + outl(solh, emu->port + DATA); + // Finally we verify that nothing interfered in fact. + if (REG_VAL_GET(WC_SAMPLECOUNTER, inl(emu->port + WC)) == + ((REG_VAL_GET(WC_SAMPLECOUNTER, wc) + 1) & REG_MASK0(WC_SAMPLECOUNTER))) { + ret = 0; + } else { + ret = -EAGAIN; + } + break; + } + // Don't block for too long + spin_unlock_irqrestore(&emu->emu_lock, flags); + udelay(1); + spin_lock_irqsave(&emu->emu_lock, flags); + } + + spin_unlock_irqrestore(&emu->emu_lock, flags); + return ret; +} void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait) { @@ -496,64 +629,3 @@ void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned outw(data, emu->port + AC97DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); } - -/* - * convert rate to pitch - */ - -unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate) -{ - static const u32 logMagTable[128] = { - 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, - 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, - 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, - 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, - 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, - 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, - 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, - 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, - 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, - 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, - 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, - 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, - 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, - 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, - 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, - 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df - }; - static const char logSlopeTable[128] = { - 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, - 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, - 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, - 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, - 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, - 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, - 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, - 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, - 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, - 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, - 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, - 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f - }; - int i; - - if (rate == 0) - return 0; /* Bail out if no leading "1" */ - rate *= 11185; /* Scale 48000 to 0x20002380 */ - for (i = 31; i > 0; i--) { - if (rate & 0x80000000) { /* Detect leading "1" */ - return (((unsigned int) (i - 15) << 20) + - logMagTable[0x7f & (rate >> 24)] + - (0x7f & (rate >> 17)) * - logSlopeTable[0x7f & (rate >> 24)]); - } - rate <<= 1; - } - - return 0; /* Should never reach this point */ -} - diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index dfb44e5e69a7..a813ef8c2f8d 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -22,15 +22,18 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) int handled = 0; int timeout = 0; - while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) { - timeout++; - orig_status = status; + while ((status = inl(emu->port + IPR)) != 0) { handled = 1; if ((status & 0xffffffff) == 0xffffffff) { dev_info(emu->card->dev, "Suspected sound card removal\n"); break; } + if (++timeout == 1000) { + dev_info(emu->card->dev, "emu10k1 irq routine failure\n"); + break; + } + orig_status = status; if (status & IPR_PCIERROR) { dev_err(emu->card->dev, "interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); @@ -44,12 +47,13 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { + struct snd_emu10k1_voice *pvoice; int voice; int voice_max = status & IPR_CHANNELNUMBERMASK; u32 val; - struct snd_emu10k1_voice *pvoice = emu->voices; val = snd_emu10k1_ptr_read(emu, CLIPL, 0); + pvoice = emu->voices; for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, CLIPH, 0); @@ -65,6 +69,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) pvoice++; } val = snd_emu10k1_ptr_read(emu, HLIPL, 0); + pvoice = emu->voices; for (voice = 0; voice <= voice_max; voice++) { if (voice == 0x20) val = snd_emu10k1_ptr_read(emu, HLIPH, 0); @@ -79,9 +84,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) val >>= 1; pvoice++; } - status &= ~IPR_CHANNELLOOP; + status &= ~(IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK); } - status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); @@ -147,31 +151,11 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) } if (status) { - unsigned int bits; dev_err(emu->card->dev, "unhandled interrupt: 0x%08x\n", status); - //make sure any interrupts we don't handle are disabled: - bits = INTE_FXDSPENABLE | - INTE_PCIERRORENABLE | - INTE_VOLINCRENABLE | - INTE_VOLDECRENABLE | - INTE_MUTEENABLE | - INTE_MICBUFENABLE | - INTE_ADCBUFENABLE | - INTE_EFXBUFENABLE | - INTE_GPSPDIFENABLE | - INTE_CDSPDIFENABLE | - INTE_INTERVALTIMERENB | - INTE_MIDITXENABLE | - INTE_MIDIRXENABLE; - if (emu->audigy) - bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; - snd_emu10k1_intr_disable(emu, bits); } outl(orig_status, emu->port + IPR); /* ack all */ } - if (timeout == 1000) - dev_info(emu->card->dev, "emu10k1 irq routine failure\n"); return IRQ_RETVAL(handled); } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index edb3f1763719..20b07117574b 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -315,10 +315,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst if (snd_BUG_ON(!hdr)) return NULL; - idx = runtime->period_size >= runtime->buffer_size ? - (emu->delay_pcm_irq * 2) : 0; mutex_lock(&hdr->block_mutex); - blk = search_empty(emu, runtime->dma_bytes + idx); + blk = search_empty(emu, runtime->dma_bytes); if (blk == NULL) { mutex_unlock(&hdr->block_mutex); return NULL; diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 2435d3ba68f7..993663fef885 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -18,29 +18,23 @@ static int snd_emu10k1_timer_start(struct snd_timer *timer) { struct snd_emu10k1 *emu; - unsigned long flags; unsigned int delay; emu = snd_timer_chip(timer); delay = timer->sticks - 1; if (delay < 5 ) /* minimum time is 5 ticks */ delay = 5; - spin_lock_irqsave(&emu->reg_lock, flags); snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB); outw(delay & TIMER_RATE_MASK, emu->port + TIMER); - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } static int snd_emu10k1_timer_stop(struct snd_timer *timer) { struct snd_emu10k1 *emu; - unsigned long flags; emu = snd_timer_chip(timer); - spin_lock_irqsave(&emu->reg_lock, flags); snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); - spin_unlock_irqrestore(&emu->reg_lock, flags); return 0; } diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index cbeb8443492c..6939498e26f0 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -23,110 +23,101 @@ * allocator uses a round robin scheme. The next free voice is tracked in * the card record and each allocation begins where the last left off. The * hardware requires stereo interleaved voices be aligned to an even/odd - * boundary. For multichannel voice allocation we ensure than the block of - * voices does not cross the 32 voice boundary. This simplifies the - * multichannel support and ensures we can use a single write to the - * (set|clear)_loop_stop registers. Otherwise (for example) the voices would - * get out of sync when pausing/resuming a stream. + * boundary. * --rlrevell */ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, - struct snd_emu10k1_voice **rvoice) + struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) { struct snd_emu10k1_voice *voice; - int i, j, k, first_voice, last_voice, skip; + int i, j, k, skip; - *rvoice = NULL; - first_voice = last_voice = 0; - for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) { + for (i = emu->next_free_voice, j = 0; j < NUM_G; i = (i + skip) % NUM_G, j += skip) { /* dev_dbg(emu->card->dev, "i %d j %d next free %d!\n", i, j, emu->next_free_voice); */ - i %= NUM_G; /* stereo voices must be even/odd */ - if ((number == 2) && (i % 2)) { - i++; + if ((number > 1) && (i % 2)) { + skip = 1; continue; } - - skip = 0; + for (k = 0; k < number; k++) { - voice = &emu->voices[(i+k) % NUM_G]; + voice = &emu->voices[i + k]; if (voice->use) { - skip = 1; - break; + skip = k + 1; + goto next; } } - if (!skip) { - /* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */ - first_voice = i; - last_voice = (i + number) % NUM_G; - emu->next_free_voice = last_voice; - break; - } - } - - if (first_voice == last_voice) - return -ENOMEM; - - for (i = 0; i < number; i++) { - voice = &emu->voices[(first_voice + i) % NUM_G]; - /* - dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n", - voice->number, idx-first_voice+1, number); - */ - voice->use = 1; - switch (type) { - case EMU10K1_PCM: - voice->pcm = 1; - break; - case EMU10K1_SYNTH: - voice->synth = 1; - break; - case EMU10K1_MIDI: - voice->midi = 1; - break; - case EMU10K1_EFX: - voice->efx = 1; - break; + + for (k = 0; k < number; k++) { + voice = &emu->voices[i + k]; + voice->use = type; + voice->epcm = epcm; + /* dev_dbg(emu->card->dev, "allocated voice %d\n", i + k); */ } + voice->last = 1; + + *rvoice = &emu->voices[i]; + emu->next_free_voice = (i + number) % NUM_G; + return 0; + + next: ; } - *rvoice = &emu->voices[first_voice]; - return 0; + return -ENOMEM; // -EBUSY would have been better +} + +static void voice_free(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *pvoice) +{ + if (pvoice->dirty) + snd_emu10k1_voice_init(emu, pvoice->number); + pvoice->interrupt = NULL; + pvoice->use = pvoice->dirty = pvoice->last = 0; + pvoice->epcm = NULL; } -int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number, - struct snd_emu10k1_voice **rvoice) +int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int count, int channels, + struct snd_emu10k1_pcm *epcm, struct snd_emu10k1_voice **rvoice) { unsigned long flags; int result; if (snd_BUG_ON(!rvoice)) return -EINVAL; - if (snd_BUG_ON(!number)) + if (snd_BUG_ON(!count)) + return -EINVAL; + if (snd_BUG_ON(!channels)) return -EINVAL; spin_lock_irqsave(&emu->voice_lock, flags); - for (;;) { - result = voice_alloc(emu, type, number, rvoice); - if (result == 0 || type == EMU10K1_SYNTH || type == EMU10K1_MIDI) - break; - - /* free a voice from synth */ - if (emu->get_synth_voice) { + for (int got = 0; got < channels; ) { + result = voice_alloc(emu, type, count, epcm, &rvoice[got]); + if (result == 0) { + got++; + /* + dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n", + rvoice[got - 1]->number, got, want); + */ + continue; + } + if (type != EMU10K1_SYNTH && emu->get_synth_voice) { + /* free a voice from synth */ result = emu->get_synth_voice(emu); if (result >= 0) { - struct snd_emu10k1_voice *pvoice = &emu->voices[result]; - pvoice->interrupt = NULL; - pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0; - pvoice->epcm = NULL; + voice_free(emu, &emu->voices[result]); + continue; } } - if (result < 0) - break; + for (int i = 0; i < got; i++) { + for (int j = 0; j < count; j++) + voice_free(emu, rvoice[i] + j); + rvoice[i] = NULL; + } + break; } spin_unlock_irqrestore(&emu->voice_lock, flags); @@ -139,14 +130,15 @@ int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *pvoice) { unsigned long flags; + int last; if (snd_BUG_ON(!pvoice)) return -EINVAL; spin_lock_irqsave(&emu->voice_lock, flags); - pvoice->interrupt = NULL; - pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0; - pvoice->epcm = NULL; - snd_emu10k1_voice_init(emu, pvoice->number); + do { + last = pvoice->last; + voice_free(emu, pvoice++); + } while (!last); spin_unlock_irqrestore(&emu->voice_lock, flags); return 0; } diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 1b078b789604..7ceaf6a7a77e 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -98,7 +98,7 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, memset(&group_state, 0, sizeof(group_state)); group_state.pipe_count = 1; - group_state.pipe_uid[0] = pipe->group_uid; + group_state.pipe_uid = pipe->group_uid; if(start) request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET; @@ -185,7 +185,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr, clock_properties.clock_mode = CM_STANDALONE; clock_properties.frequency = rate; clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */ - clock_properties.uid_caller[0] = pipe->group_uid; + clock_properties.uid_caller = pipe->group_uid; dev_dbg(&mgr->pci->dev, "mixart_set_clock to %d kHz\n", rate); @@ -565,8 +565,8 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form stream_param.pipe_count = 1; /* set to 1 */ stream_param.stream_count = 1; /* set to 1 */ - stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid; - stream_param.stream_desc[0].stream_idx = stream->substream->number; + stream_param.stream_desc.uid_pipe = stream->pipe->group_uid; + stream_param.stream_desc.stream_idx = stream->substream->number; request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM; request.uid = (struct mixart_uid){0,0}; diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h index 2f0e29ed5d63..d39233e0e070 100644 --- a/sound/pci/mixart/mixart_core.h +++ b/sound/pci/mixart/mixart_core.h @@ -231,7 +231,7 @@ struct mixart_group_state_req u64 scheduler; u32 reserved4np[2]; u32 pipe_count; /* set to 1 for instance */ - struct mixart_uid pipe_uid[1]; /* could be an array[pipe_count] */ + struct mixart_uid pipe_uid; /* could be an array[pipe_count], in theory */ } __attribute__((packed)); struct mixart_group_state_resp @@ -314,7 +314,7 @@ struct mixart_clock_properties u32 format; u32 board_mask; u32 nb_callers; /* set to 1 (see below) */ - struct mixart_uid uid_caller[1]; + struct mixart_uid uid_caller; } __attribute__((packed)); struct mixart_clock_properties_resp @@ -401,8 +401,7 @@ struct mixart_stream_param_desc u32 reserved4np[3]; u32 pipe_count; /* set to 1 (array size !) */ u32 stream_count; /* set to 1 (array size !) */ - struct mixart_txx_stream_desc stream_desc[1]; /* only one stream per command, but this could be an array */ - + struct mixart_txx_stream_desc stream_desc; /* only one stream per command, but this could be an array, in theory */ } __attribute__((packed)); diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig index 10291c43cb18..2e3dfc1ff540 100644 --- a/sound/pcmcia/Kconfig +++ b/sound/pcmcia/Kconfig @@ -4,6 +4,7 @@ menuconfig SND_PCMCIA bool "PCMCIA sound devices" depends on PCMCIA + depends on HAS_IOPORT default y help Support for sound devices connected via the PCMCIA bus. |