diff options
Diffstat (limited to 'sound/pci/emu10k1')
-rw-r--r-- | sound/pci/emu10k1/emu10k1.c | 127 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_callback.c | 257 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 946 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_synth.c | 11 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1x.c | 194 | ||||
-rw-r--r-- | sound/pci/emu10k1/emufx.c | 952 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumixer.c | 1806 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumpu401.c | 52 | ||||
-rw-r--r-- | sound/pci/emu10k1/emupcm.c | 1155 | ||||
-rw-r--r-- | sound/pci/emu10k1/emuproc.c | 542 | ||||
-rw-r--r-- | sound/pci/emu10k1/io.c | 423 | ||||
-rw-r--r-- | sound/pci/emu10k1/irq.c | 81 | ||||
-rw-r--r-- | sound/pci/emu10k1/memory.c | 29 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.c | 177 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.h | 58 | ||||
-rw-r--r-- | sound/pci/emu10k1/p17v.h | 5 | ||||
-rw-r--r-- | sound/pci/emu10k1/timer.c | 37 | ||||
-rw-r--r-- | sound/pci/emu10k1/tina2.h | 1 | ||||
-rw-r--r-- | sound/pci/emu10k1/voice.c | 148 |
19 files changed, 3443 insertions, 3558 deletions
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 29b7720d7961..fe72e7d77241 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -2,9 +2,7 @@ /* * The driver for the EMU10K1 (SB Live!) based soundcards * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> - * Added support for Audigy 2 Value. + * James Courtier-Dutton <James@superbug.co.uk> */ #include <linux/init.h> @@ -18,8 +16,6 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("EMU10K1"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," - "{Creative Labs,SB Audigy}}"); #if IS_ENABLED(CONFIG_SND_SEQUENCER) #define ENABLE_SYNTH @@ -36,7 +32,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."); @@ -58,8 +53,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 */ @@ -70,17 +63,6 @@ static const struct pci_device_id snd_emu10k1_ids[] = { { 0, } }; -/* - * Audigy 2 Value notes: - * A_IOCFG Input (GPIO) - * 0x400 = Front analog jack plugged in. (Green socket) - * 0x1000 = Read analog jack plugged in. (Black socket) - * 0x2000 = Center/LFE analog jack plugged in. (Orange socket) - * A_IOCFG Output (GPIO) - * 0x60 = Sound out of front Left. - * Win sets it to 0xXX61 - */ - MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids); static int snd_card_emu10k1_probe(struct pci_dev *pci, @@ -101,56 +83,68 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, - 0, &card); + err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(*emu), &card); if (err < 0) return err; + emu = card->private_data; + if (max_buffer_size[dev] < 32) max_buffer_size[dev] = 32; else if (max_buffer_size[dev] > 1024) max_buffer_size[dev] = 1024; - if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], - (long)max_buffer_size[dev] * 1024 * 1024, - enable_ir[dev], subsystem[dev], - &emu)) < 0) - goto error; - card->private_data = emu; - emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; - if ((err = snd_emu10k1_pcm(emu, 0)) < 0) - goto error; - if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0) - goto error; - if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0) - goto error; + err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], + (long)max_buffer_size[dev] * 1024 * 1024, + enable_ir[dev], subsystem[dev]); + if (err < 0) + return err; + err = snd_emu10k1_pcm(emu, 0); + 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; /* This stores the periods table. */ if (emu->card_capabilities->ca0151_chip) { /* P16V */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - 1024, &emu->p16v_buffer); - if (err < 0) - goto error; + emu->p16v_buffer = + snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, 1024); + if (!emu->p16v_buffer) + return -ENOMEM; } - if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) - goto error; + err = snd_emu10k1_mixer(emu, 0, 3); + if (err < 0) + return err; - if ((err = snd_emu10k1_timer(emu, 0)) < 0) - goto error; + err = snd_emu10k1_timer(emu, 0); + if (err < 0) + return err; - if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0) - goto error; + err = snd_emu10k1_pcm_multi(emu, 3); + if (err < 0) + return err; if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_pcm(emu, 4)) < 0) - goto error; + err = snd_p16v_pcm(emu, 4); + if (err < 0) + return err; } if (emu->audigy) { - if ((err = snd_emu10k1_audigy_midi(emu)) < 0) - goto error; + err = snd_emu10k1_audigy_midi(emu); + if (err < 0) + return err; } else { - if ((err = snd_emu10k1_midi(emu)) < 0) - goto error; + err = snd_emu10k1_midi(emu); + if (err < 0) + return err; } - if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0) - goto error; + err = snd_emu10k1_fx8010_new(emu, 0); + if (err < 0) + return err; #ifdef ENABLE_SYNTH if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 || @@ -168,35 +162,23 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, } #endif - strlcpy(card->driver, emu->card_capabilities->driver, + strscpy(card->driver, emu->card_capabilities->driver, sizeof(card->driver)); - strlcpy(card->shortname, emu->card_capabilities->name, + strscpy(card->shortname, emu->card_capabilities->name, sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", card->shortname, emu->revision, emu->serial, emu->port, emu->irq); - if ((err = snd_card_register(card)) < 0) - goto error; - - if (emu->card_capabilities->emu_model) - schedule_delayed_work(&emu->emu1010.firmware_work, 0); + err = snd_card_register(card); + if (err < 0) + return err; pci_set_drvdata(pci, card); dev++; return 0; - - error: - snd_card_free(card); - return err; -} - -static void snd_card_emu10k1_remove(struct pci_dev *pci) -{ - snd_card_free(pci_get_drvdata(pci)); } - #ifdef CONFIG_PM_SLEEP static int snd_emu10k1_suspend(struct device *dev) { @@ -207,7 +189,8 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; - cancel_delayed_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.clock_work); snd_ac97_suspend(emu->ac97); @@ -237,9 +220,6 @@ static int snd_emu10k1_resume(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D0); - if (emu->card_capabilities->emu_model) - schedule_delayed_work(&emu->emu1010.firmware_work, 0); - return 0; } @@ -253,7 +233,6 @@ static struct pci_driver emu10k1_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, - .remove = snd_card_emu10k1_remove, .driver = { .pm = SND_EMU10K1_PM_OPS, }, diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index 07471c3dcbed..d36234b88fb4 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -33,9 +33,9 @@ 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); +static int get_pitch_shift(struct snd_emux *emu); /* * Ensure a value is between two points @@ -59,6 +59,7 @@ static const struct snd_emux_operators emu10k1_ops = { .free_voice = free_voice, .sample_new = snd_emu10k1_sample_new, .sample_free = snd_emu10k1_sample_free, + .get_pitch_shift = get_pitch_shift, }; void @@ -90,7 +91,8 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) if (best[i].voice >= 0) { int ch; vp = &emu->voices[best[i].voice]; - if ((ch = vp->ch) < 0) { + ch = vp->ch; + if (ch < 0) { /* dev_warn(emu->card->dev, "synth_get_voice: ch < 0 (%d) ??", i); @@ -115,14 +117,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 = 0x8000 | (unsigned char)vp->reg.parm.modrelease; - snd_emu10k1_ptr_write(hw, DCYSUSM, vp->ch, dcysusv); - dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease | 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); } @@ -137,7 +138,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, 0x807f | 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; @@ -160,11 +167,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; @@ -190,13 +192,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); } @@ -253,7 +255,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; } @@ -287,7 +289,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++; @@ -308,6 +310,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; @@ -345,114 +348,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, 0x0000); - snd_emu10k1_ptr_write(hw, VTFT, ch, 0x0000FFFF); - snd_emu10k1_ptr_write(hw, CVCF, ch, 0x0000FFFF); - 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, - /* 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 | 0xff00); + /* lfo1 pitch & cutoff shift */ + FMMOD, make_fmmod(vp), + /* lfo1 volume & freq */ + TREMFRQ, vp->reg.parm.tremfrq, + /* lfo2 pitch & freq */ + FM2FRQ2, make_fm2frq2(vp), + + /* 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; } @@ -462,7 +449,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; @@ -477,24 +464,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; @@ -504,15 +492,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; @@ -522,16 +508,13 @@ 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); + return ((unsigned char)pitch << 8) | freq; } -/* set filterQ */ -static void -set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp) +static int get_pitch_shift(struct snd_emux *emu) { - unsigned int val; - val = snd_emu10k1_ptr_read(hw, CCCA, vp->ch) & ~CCCA_RESONANCE; - val |= (vp->reg.parm.filterQ << 28); - snd_emu10k1_ptr_write(hw, CCCA, vp->ch, val); + struct snd_emu10k1 *hw = emu->hw; + + return (hw->card_capabilities->emu_model && + hw->emu1010.word_clock == 44100) ? 0 : -501; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index bd70e112ffd7..de5c41e578e1 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -1,19 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for control of EMU10K1 chips - * - * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> - * Added support for Audigy 2 Value. - * Added EMU 1010 support. - * General bug fixes and enhancements. * - * BUGS: - * -- - * - * TODO: - * -- + * Routines for control of EMU10K1 chips */ #include <linux/sched.h> @@ -57,46 +49,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, 0xffff); - snd_emu10k1_ptr_write(emu, CVCF, ch, 0xffff); - 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, 0xffff); - 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, 0x4c, ch, 0); /* ?? */ - snd_emu10k1_ptr_write(emu, 0x4d, ch, 0); /* ?? */ - snd_emu10k1_ptr_write(emu, 0x4e, ch, 0); /* ?? */ - snd_emu10k1_ptr_write(emu, 0x4f, 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); } } @@ -140,7 +135,7 @@ static const unsigned int i2c_adc_init[][2] = { { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */ }; -static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) +static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir) { unsigned int silent_page; int ch; @@ -150,20 +145,26 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) 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); - 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 */ @@ -177,17 +178,17 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) 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->ca0151_chip) { /* audigy2 */ + if (emu->card_capabilities->emu_model) { + } else if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Hacks for Alice3 to work independent of haP16V driver */ /* Setup SRCMulti_I2S SamplingRate */ - tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); - tmp &= 0xfffff1ff; - tmp |= (0x2<<9); - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, 0, A_I2S_CAPTURE_96000); /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); @@ -199,32 +200,26 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) outl(0x0201, emu->port + HCFG2); /* Set playback routing. */ snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4); - } - if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ + } else if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ dev_info(emu->card->dev, "Audigy2 value: Special config.\n"); /* Setup SRCMulti_I2S SamplingRate */ - tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); - tmp &= 0xfffff1ff; - tmp |= (0x2<<9); - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, 0, A_I2S_CAPTURE_96000); /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ - outl(0x600000, emu->port + 0x20); - outl(0x14, emu->port + 0x24); + snd_emu10k1_ptr20_write(emu, P17V_SRCSel, 0, 0x14); /* Setup SRCMulti Input Audio Enable */ - outl(0x7b0000, emu->port + 0x20); - outl(0xFF000000, emu->port + 0x24); + snd_emu10k1_ptr20_write(emu, P17V_MIXER_I2S_ENABLE, 0, 0xFF000000); /* Setup SPDIF Out Audio Enable */ /* The Audigy 2 Value has a separate SPDIF out, * so no need for a mixer switch */ - outl(0x7a0000, emu->port + 0x20); - outl(0xFF000000, emu->port + 0x24); - tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */ - outl(tmp, emu->port + A_IOCFG); + snd_emu10k1_ptr20_write(emu, P17V_MIXER_SPDIF_ENABLE, 0, 0xFF000000); + + tmp = inw(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */ + outw(tmp, emu->port + A_IOCFG); } if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */ int size, n; @@ -244,15 +239,15 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) * GPIO6: Unknown * GPIO7: Unknown */ - outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ + outw(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ } if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ int size, n; snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); - tmp = inl(emu->port + A_IOCFG); - outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ - tmp = inl(emu->port + A_IOCFG); + tmp = inw(emu->port + A_IOCFG); + outw(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ + tmp = inw(emu->port + A_IOCFG); size = ARRAY_SIZE(i2c_adc_init); for (n = 0; n < size; n++) snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); @@ -265,7 +260,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ - snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ + snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_256K); /* taken from original driver */ silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0); for (ch = 0; ch < NUM_G; ch++) { @@ -308,12 +303,12 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } else if (emu->card_capabilities->i2c_adc) { ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { - unsigned int reg = inl(emu->port + A_IOCFG); - outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); + u16 reg = inw(emu->port + A_IOCFG); + outw(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); udelay(500); - outl(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG); + outw(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG); udelay(100); - outl(reg, emu->port + A_IOCFG); + outw(reg, emu->port + A_IOCFG); } else { unsigned int reg = inl(emu->port + HCFG); outl(reg | HCFG_GPOUT2, emu->port + HCFG); @@ -329,8 +324,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } else if (emu->card_capabilities->i2c_adc) { ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { /* enable analog output */ - unsigned int reg = inl(emu->port + A_IOCFG); - outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); + u16 reg = inw(emu->port + A_IOCFG); + outw(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); } if (emu->address_mode == 0) { @@ -354,19 +349,19 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) } else if (emu->card_capabilities->i2c_adc) { ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ } else if (emu->audigy) { - outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); + outw(inw(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ /* Unmute Analog now. Set GPO6 to 1 for Apollo. * This has to be done after init ALice3 I2SOut beyond 48KHz. * So, sequence is important. */ - outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG); + outw(inw(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG); } else if (emu->card_capabilities->ca0108_chip) { /* audigy2 value */ /* Unmute Analog now. */ - outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG); + outw(inw(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG); } else { /* Disable routing from AC97 line out to Front speakers */ - outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); + outw(inw(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } @@ -388,7 +383,10 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) } #endif - snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); + if (emu->card_capabilities->emu_model) + snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE); + else + snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); } int snd_emu10k1_done(struct snd_emu10k1 *emu) @@ -398,41 +396,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; } @@ -651,26 +656,26 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, const struct firmware *fw_entry) { int n, i; - int reg; - int value; - __always_unused unsigned int write_post; - unsigned long flags; + u16 reg; + u8 value; + __always_unused u16 write_post; if (!fw_entry) return -EIO; /* The FPGA is a Xilinx Spartan IIE XC2S50E */ + /* On E-MU 0404b it is a Xilinx Spartan III XC3S50 */ /* GPIO7 -> FPGA PGMN * GPIO6 -> FPGA CCLK * GPIO5 -> FPGA DIN * FPGA CONFIG OFF -> FPGA PGMN */ - spin_lock_irqsave(&emu->emu_lock, flags); - outl(0x00, emu->port + A_IOCFG); /* Set PGMN low for 1uS. */ - write_post = inl(emu->port + A_IOCFG); + spin_lock_irq(&emu->emu_lock); + outw(0x00, emu->port + A_GPIO); /* Set PGMN low for 100uS. */ + write_post = inw(emu->port + A_GPIO); udelay(100); - outl(0x80, emu->port + A_IOCFG); /* Leave bit 7 set during netlist setup. */ - write_post = inl(emu->port + A_IOCFG); + outw(0x80, emu->port + A_GPIO); /* Leave bit 7 set during netlist setup. */ + write_post = inw(emu->port + A_GPIO); udelay(100); /* Allow FPGA memory to clean */ for (n = 0; n < fw_entry->size; n++) { value = fw_entry->data[n]; @@ -679,16 +684,16 @@ static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, if (value & 0x1) reg = reg | 0x20; value = value >> 1; - outl(reg, emu->port + A_IOCFG); - write_post = inl(emu->port + A_IOCFG); - outl(reg | 0x40, emu->port + A_IOCFG); - write_post = inl(emu->port + A_IOCFG); + outw(reg, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + outw(reg | 0x40, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); } } /* After programming, set GPIO bit 4 high again. */ - outl(0x10, emu->port + A_IOCFG); - write_post = inl(emu->port + A_IOCFG); - spin_unlock_irqrestore(&emu->emu_lock, flags); + outw(0x10, emu->port + A_GPIO); + write_post = inw(emu->port + A_GPIO); + spin_unlock_irq(&emu->emu_lock); return 0; } @@ -734,14 +739,13 @@ static void emu1010_firmware_work(struct work_struct *work) int err; emu = container_of(work, struct snd_emu10k1, - emu1010.firmware_work.work); + emu1010.firmware_work); if (emu->card->shutdown) return; #ifdef CONFIG_PM_SLEEP if (emu->suspend) return; #endif - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ @@ -752,13 +756,8 @@ static void emu1010_firmware_work(struct work_struct *work) EMU_HANA_FPGA_CONFIG_AUDIODOCK); err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); if (err < 0) - goto next; - + return; snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); - dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp); - /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); dev_info(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); @@ -767,7 +766,7 @@ static void emu1010_firmware_work(struct work_struct *work) dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", tmp); - goto next; + return; } dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n"); @@ -779,44 +778,51 @@ static void emu1010_firmware_work(struct work_struct *work) msleep(10); /* Unmute all. Default is muted after a firmware load */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - } else if (!reg && emu->emu1010.last_reg) { + } +} + +static void emu1010_clock_work(struct work_struct *work) +{ + struct snd_emu10k1 *emu; + struct snd_ctl_elem_id id; + + emu = container_of(work, struct snd_emu10k1, + emu1010.clock_work); + if (emu->card->shutdown) + return; +#ifdef CONFIG_PM_SLEEP + if (emu->suspend) + return; +#endif + + spin_lock_irq(&emu->reg_lock); + // This is the only thing that can actually happen. + emu->emu1010.clock_source = emu->emu1010.clock_fallback; + emu->emu1010.wclock = 1 - emu->emu1010.clock_source; + snd_emu1010_update_clock(emu); + spin_unlock_irq(&emu->reg_lock); + snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0); + snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id); +} + +static void emu1010_interrupt(struct snd_emu10k1 *emu) +{ + u32 sts; + + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts); + if (sts & EMU_HANA_IRQ_DOCK_LOST) { /* Audio Dock removed */ dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); - /* Unmute all */ + /* The hardware auto-mutes all, so we unmute again */ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + } else if (sts & EMU_HANA_IRQ_DOCK) { + schedule_work(&emu->emu1010.firmware_work); } - - next: - emu->emu1010.last_reg = reg; - if (!emu->card->shutdown) - schedule_delayed_work(&emu->emu1010.firmware_work, - msecs_to_jiffies(1000)); + if (sts & EMU_HANA_IRQ_WCLK_CHANGED) + schedule_work(&emu->emu1010.clock_work); } /* - * EMU-1010 - details found out from this driver, official MS Win drivers, - * testing the card: - * - * Audigy2 (aka Alice2): - * --------------------- - * * communication over PCI - * * conversion of 32-bit data coming over EMU32 links from HANA FPGA - * to 2 x 16-bit, using internal DSP instructions - * * slave mode, clock supplied by HANA - * * linked to HANA using: - * 32 x 32-bit serial EMU32 output channels - * 16 x EMU32 input channels - * (?) x I2S I/O channels (?) - * - * FPGA (aka HANA): - * --------------- - * * provides all (?) physical inputs and outputs of the card - * (ADC, DAC, SPDIF I/O, ADAT I/O, etc.) - * * provides clock signal for the card and Alice2 - * * two crystals - for 44.1kHz and 48kHz multiples - * * provides internal routing of signal sources to signal destinations - * * inputs/outputs to Alice2 - see above - * * Current status of the driver: * ---------------------------- * * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz) @@ -826,29 +832,14 @@ 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; dev_info(emu->card->dev, "emu1010: Special config.\n"); - /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, - * Lock Sound Memory Cache, Lock Tank Memory Cache, - * Mute all codecs. - */ - outl(0x0005a00c, emu->port + HCFG); - /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, - * Lock Tank Memory Cache, - * Mute all codecs. - */ - outl(0x0005a004, emu->port + HCFG); - /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, - * Mute all codecs. - */ - outl(0x0005a000, emu->port + HCFG); - /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, - * Mute all codecs. - */ - outl(0x0005a000, emu->port + HCFG); + + /* Mute, and disable audio and lock cache, just in case. + * Proper init follows in snd_emu10k1_init(). */ + outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); @@ -860,7 +851,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* FPGA netlist already present so clear it */ /* Return to programming mode */ - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_HANA); } snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg); @@ -897,339 +888,53 @@ 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); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp); - /* Optical -> ADAT I/O */ - /* 0 : SPDIF - * 1 : ADAT - */ - emu->emu1010.optical_in = 1; /* IN_ADAT */ - emu->emu1010.optical_out = 1; /* IN_ADAT */ - tmp = 0; - tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | - (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); + if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) + schedule_work(&emu->emu1010.firmware_work); + 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); - snd_emu1010_fpga_read(emu, EMU_HANA_ADC_PADS, &tmp); /* Set no attenuation on Audio Dock pads. */ - snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, 0x00); emu->emu1010.adc_pads = 0x00; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, emu->emu1010.adc_pads); /* Unmute Audio dock DACs, Headphone source DAC-4. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); - snd_emu1010_fpga_read(emu, EMU_HANA_DAC_PADS, &tmp); + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, EMU_HANA_DOCK_PHONES_192_DAC4); /* DAC PADs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, 0x0f); - emu->emu1010.dac_pads = 0x0f; - snd_emu1010_fpga_read(emu, EMU_HANA_DOCK_MISC, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, 0x30); - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); + emu->emu1010.dac_pads = EMU_HANA_DOCK_DAC_PAD1 | EMU_HANA_DOCK_DAC_PAD2 | + EMU_HANA_DOCK_DAC_PAD3 | EMU_HANA_DOCK_DAC_PAD4; + snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, emu->emu1010.dac_pads); /* SPDIF Format. Set Consumer mode, 24bit, copy enable */ - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); + snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, EMU_HANA_SPDIF_MODE_RX_INVALID); /* MIDI routing */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); - /* Unknown. */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); - /* IRQ Enable: All on */ - /* snd_emu1010_fpga_write(emu, 0x09, 0x0f ); */ - /* IRQ Enable: All off */ - snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2); + snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2); - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - dev_info(emu->card->dev, "emu1010: Card options3 = 0x%x\n", reg); + emu->gpio_interrupt = emu1010_interrupt; + // Note: The Audigy INTE is set later + snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, + EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs + + emu->emu1010.clock_source = 1; /* 48000 */ + emu->emu1010.clock_fallback = 1; /* 48000 */ /* Default WCLK set to 48kHz. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00); + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K); /* Word Clock source, Internal 48kHz x1 */ + emu->emu1010.wclock = EMU_HANA_WCLOCK_INT_48K; snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ - /* Audio Dock LEDs. */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); + snd_emu1010_update_clock(emu); -#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); - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x01); /* Unmute all */ - - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); - - /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, - * Lock Sound Memory Cache, Lock Tank Memory Cache, - * Mute all codecs. - */ - outl(0x0000a000, emu->port + HCFG); - /* AC97 1.03, Any 32Meg of 2Gig address, Auto-Mute, EMU32 Slave, - * Lock Sound Memory Cache, Lock Tank Memory Cache, - * Un-Mute all codecs. - */ - outl(0x0000a001, emu->port + HCFG); - - /* Initial boot complete. Now patches */ - - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, 0x19); /* MIDI Route */ - snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, 0x0c); /* Unknown */ - snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); - snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ - -#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; - } - /* TEMP: Select SPDIF in/out */ - /* snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, 0x0); */ /* Output spdif */ - - /* TEMP: Select 48kHz SPDIF out */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x0); /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x0); /* Default fallback clock 48kHz */ - /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K); - /* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */ - emu->emu1010.internal_clock = 1; /* 48000 */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 0x12); /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, 0x1); /* Unmute all */ - /* snd_emu1010_fpga_write(emu, 0x7, 0x0); */ /* Mute all */ - /* snd_emu1010_fpga_write(emu, 0x7, 0x1); */ /* Unmute all */ - /* snd_emu1010_fpga_write(emu, 0xe, 0x12); */ /* Set LEDs on Audio Dock */ + // 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); return 0; } @@ -1242,8 +947,10 @@ static int alloc_pm_buffer(struct snd_emu10k1 *emu); static void free_pm_buffer(struct snd_emu10k1 *emu); #endif -static int snd_emu10k1_free(struct snd_emu10k1 *emu) +static void snd_emu10k1_free(struct snd_card *card) { + struct snd_emu10k1 *emu = card->private_data; + if (emu->port) { /* avoid access to already used hardware */ snd_emu10k1_fx8010_tram_setup(emu, 0); snd_emu10k1_done(emu); @@ -1253,11 +960,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } - cancel_delayed_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.firmware_work); + cancel_work_sync(&emu->emu1010.clock_work); release_firmware(emu->firmware); release_firmware(emu->dock_fw); - if (emu->irq >= 0) - free_irq(emu->irq, emu); snd_util_memhdr_free(emu->memhdr); if (emu->silent_page.area) snd_dma_free_pages(&emu->silent_page); @@ -1268,19 +974,6 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) #ifdef CONFIG_PM_SLEEP free_pm_buffer(emu); #endif - if (emu->port) - pci_release_regions(emu->pci); - if (emu->card_capabilities->ca0151_chip) /* P16V */ - snd_p16v_free(emu); - pci_disable_device(emu->pci); - kfree(emu); - return 0; -} - -static int snd_emu10k1_dev_free(struct snd_device *device) -{ - struct snd_emu10k1 *emu = device->device_data; - return snd_emu10k1_free(emu); } static const struct snd_emu_chip_details emu_chip_details[] = { @@ -1356,6 +1049,15 @@ static const struct snd_emu_chip_details emu_chip_details[] = { * AC97: STAC9750 * CA0151: None */ + /* + * A_IOCFG Input (GPIO) + * 0x400 = Front analog jack plugged in. (Green socket) + * 0x1000 = Rear analog jack plugged in. (Black socket) + * 0x2000 = Center/LFE analog jack plugged in. (Orange socket) + * A_IOCFG Output (GPIO) + * 0x60 = Sound out of front Left. + * Win sets it to 0xXX61 + */ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, .driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]", .id = "Audigy2", @@ -1404,9 +1106,12 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spi_dac = 1, .i2c_adc = 1, .spk71 = 1} , + /* This is MAEM8950 "Mana" */ + /* Attach MicroDock[M] to make it an E-MU 1616[m]. */ + /* Does NOT support sync daughter card (obviously). */ /* Tested by James@superbug.co.uk 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, @@ -1414,9 +1119,12 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spk71 = 1 , .emu_model = EMU_MODEL_EMU1616}, /* Tested by James@superbug.co.uk 4th Nov 2007. */ - /* This is MAEM8960, 0202 is MAEM 8980 */ + /* This is MAEM8960 "Hana3", 0202 is MAEM8980 */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR a + * 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, @@ -1424,47 +1132,62 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */ /* Tested by Maxim Kachur <mcdebugger@duganet.ru> 17th Oct 2012. */ /* This is MAEM8986, 0202 is MAEM8980 */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR a + * MicroDockM to make it an E-MU 1616m. The non-m + * version was never sold with this card, but should + * 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, .spk71 = 1, .emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */ /* Tested by James@superbug.co.uk 8th July 2005. */ - /* This is MAEM8810, 0202 is MAEM8820 */ + /* This is MAEM8810 "Hana", 0202 is MAEM8820 "Hamoa" */ + /* Attach 0202 daughter card to make it an E-MU 1212m, OR an + * 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, .spk71 = 1, .emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */ - /* EMU0404b */ + /* This is MAEM8852 "HanaLiteLite" */ + /* Supports sync daughter card. */ + /* Tested by oswald.buddenhagen@gmx.de 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 James@superbug.co.uk 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 */ - /* Note that all E-mu cards require kernel 2.6 or newer. */ {.vendor = 0x1102, .device = 0x0008, .driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]", .id = "Audigy2", @@ -1545,6 +1268,8 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .adc_1361t = 1, /* 24 bit capture instead of 16bit */ .ac97_chip = 1} , + /* Audigy 2 Platinum EX */ + /* Win driver sets A_IOCFG output to 0x1c00 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, .driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]", .id = "Audigy2", @@ -1565,6 +1290,8 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .spdif_bug = 1, .invert_shared_spdif = 1, /* digital/analog switch swapped */ .ac97_chip = 1} , + /* Audigy 2 Platinum */ + /* Win driver sets A_IOCFG output to 0xa00 */ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]", .id = "Audigy2", @@ -1670,6 +1397,9 @@ static const struct snd_emu_chip_details emu_chip_details[] = { .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , + /* SB Live! Platinum */ + /* Win driver sets A_IOCFG output to 0 */ + /* Tested by Jonathan Dowland <jon@dow.land> Apr 2023. */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102, .driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]", .id = "Live", @@ -1719,7 +1449,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} , @@ -1764,11 +1494,8 @@ static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu) emu->iommu_workaround = false; - if (!iommu_present(emu->card->dev->bus)) - return; - domain = iommu_get_domain_for_dev(emu->card->dev); - if (domain && domain->type == IOMMU_DOMAIN_IDENTITY) + if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY) return; dev_notice(emu->card->dev, @@ -1782,32 +1509,22 @@ int snd_emu10k1_create(struct snd_card *card, unsigned short extout_mask, long max_cache_bytes, int enable_ir, - uint subsystem, - struct snd_emu10k1 **remu) + uint subsystem) { - struct snd_emu10k1 *emu; + struct snd_emu10k1 *emu = card->private_data; int idx, err; int is_audigy; size_t page_table_size; __le32 *pgtbl; unsigned int silent_page; const struct snd_emu_chip_details *c; - static const struct snd_device_ops ops = { - .dev_free = snd_emu10k1_dev_free, - }; - - *remu = NULL; /* enable PCI device */ - err = pci_enable_device(pci); + err = pcim_enable_device(pci); if (err < 0) return err; - emu = kzalloc(sizeof(*emu), GFP_KERNEL); - if (emu == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } + card->private_free = snd_emu10k1_free; emu->card = card; spin_lock_init(&emu->reg_lock); spin_lock_init(&emu->emu_lock); @@ -1823,7 +1540,8 @@ int snd_emu10k1_create(struct snd_card *card, emu->irq = -1; emu->synth = NULL; emu->get_synth_voice = NULL; - INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); + INIT_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); + INIT_WORK(&emu->emu1010.clock_work, emu1010_clock_work); /* read revision & serial */ emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); @@ -1850,8 +1568,6 @@ int snd_emu10k1_create(struct snd_card *card, } if (c->vendor == 0) { dev_err(card->dev, "emu10k1: Card not recognised\n"); - kfree(emu); - pci_disable_device(pci); return -ENOENT; } emu->card_capabilities = c; @@ -1869,7 +1585,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->serial); if (!*card->id && c->id) - strlcpy(card->id, c->id, sizeof(card->id)); + strscpy(card->id, c->id, sizeof(card->id)); is_audigy = emu->audigy = c->emu10k2_chip; @@ -1883,8 +1599,6 @@ int snd_emu10k1_create(struct snd_card *card, dev_err(card->dev, "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); - kfree(emu); - pci_disable_device(pci); return -ENXIO; } if (is_audigy) @@ -1893,11 +1607,8 @@ int snd_emu10k1_create(struct snd_card *card, emu->gpr_base = FXGPREGBASE; err = pci_request_regions(pci, "EMU10K1"); - if (err < 0) { - kfree(emu); - pci_disable_device(pci); + if (err < 0) return err; - } emu->port = pci_resource_start(pci, 0); emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; @@ -1905,10 +1616,8 @@ int snd_emu10k1_create(struct snd_card *card, page_table_size = sizeof(u32) * (emu->address_mode ? MAXPAGES1 : MAXPAGES0); if (snd_emu10k1_alloc_pages_maybe_wider(emu, page_table_size, - &emu->ptb_pages) < 0) { - err = -ENOMEM; - goto error; - } + &emu->ptb_pages) < 0) + return -ENOMEM; dev_dbg(card->dev, "page table address range is %.8lx:%.8lx\n", (unsigned long)emu->ptb_pages.addr, (unsigned long)(emu->ptb_pages.addr + emu->ptb_pages.bytes)); @@ -1917,36 +1626,31 @@ int snd_emu10k1_create(struct snd_card *card, emu->max_cache_pages)); emu->page_addr_table = vmalloc(array_size(sizeof(unsigned long), emu->max_cache_pages)); - if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { - err = -ENOMEM; - goto error; - } + if (!emu->page_ptr_table || !emu->page_addr_table) + return -ENOMEM; if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE, - &emu->silent_page) < 0) { - err = -ENOMEM; - goto error; - } + &emu->silent_page) < 0) + return -ENOMEM; dev_dbg(card->dev, "silent page range is %.8lx:%.8lx\n", (unsigned long)emu->silent_page.addr, (unsigned long)(emu->silent_page.addr + emu->silent_page.bytes)); emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE); - if (emu->memhdr == NULL) { - err = -ENOMEM; - goto error; - } + if (!emu->memhdr) + return -ENOMEM; emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) - sizeof(struct snd_util_memblk); pci_set_master(pci); - emu->fx8010.fxbus_mask = 0x303f; + // The masks are not used for Audigy. + // FIXME: these should come from the card_capabilites table. if (extin_mask == 0) - extin_mask = 0x3fcf; + extin_mask = 0x3fcf; // EXTIN_* if (extout_mask == 0) - extout_mask = 0x7fff; + extout_mask = 0x7fff; // EXTOUT_* emu->fx8010.extin_mask = extin_mask; emu->fx8010.extout_mask = extout_mask; emu->enable_ir = enable_ir; @@ -1954,18 +1658,16 @@ int snd_emu10k1_create(struct snd_card *card, if (emu->card_capabilities->ca_cardbus_chip) { err = snd_emu10k1_cardbus_init(emu); if (err < 0) - goto error; + return err; } if (emu->card_capabilities->ecard) { err = snd_emu10k1_ecard_init(emu); if (err < 0) - goto error; + return err; } else if (emu->card_capabilities->emu_model) { err = snd_emu10k1_emu1010_init(emu); - if (err < 0) { - snd_emu10k1_free(emu); + if (err < 0) return err; - } } else { /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version does not support this, it shouldn't do any harm */ @@ -1979,11 +1681,9 @@ int snd_emu10k1_create(struct snd_card *card, emu->fx8010.etram_pages.bytes = 0; /* irq handler must be registered after I/O ports are activated */ - if (request_irq(pci->irq, snd_emu10k1_interrupt, IRQF_SHARED, - KBUILD_MODNAME, emu)) { - err = -EBUSY; - goto error; - } + if (devm_request_irq(&pci->dev, pci->irq, snd_emu10k1_interrupt, + IRQF_SHARED, KBUILD_MODNAME, emu)) + return -EBUSY; emu->irq = pci->irq; card->sync_irq = emu->irq; @@ -2015,40 +1715,28 @@ int snd_emu10k1_create(struct snd_card *card, pgtbl[idx] = cpu_to_le32(silent_page | idx); /* set up voice indices */ - for (idx = 0; idx < NUM_G; idx++) { - emu->voices[idx].emu = emu; + for (idx = 0; idx < NUM_G; idx++) emu->voices[idx].number = idx; - } - err = snd_emu10k1_init(emu, enable_ir, 0); + err = snd_emu10k1_init(emu, enable_ir); if (err < 0) - goto error; + return err; #ifdef CONFIG_PM_SLEEP err = alloc_pm_buffer(emu); if (err < 0) - goto error; + return err; #endif /* Initialize the effect engine */ err = snd_emu10k1_init_efx(emu); if (err < 0) - goto error; + return err; snd_emu10k1_audio_enable(emu); - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops); - if (err < 0) - goto error; - #ifdef CONFIG_SND_PROC_FS snd_emu10k1_proc_init(emu); #endif - - *remu = emu; return 0; - - error: - snd_emu10k1_free(emu); - return err; } #ifdef CONFIG_PM_SLEEP @@ -2062,7 +1750,7 @@ static const unsigned char saved_regs[] = { 0xff /* end */ }; static const unsigned char saved_regs_audigy[] = { - A_ADCIDX, A_MICIDX, A_FXWC1, A_FXWC2, A_SAMPLE_RATE, + A_ADCIDX, A_MICIDX, A_FXWC1, A_FXWC2, A_EHC, A_FXRT2, A_SENDAMOUNTS, A_FXRT1, 0xff /* end */ }; @@ -2109,7 +1797,7 @@ void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu) *val = snd_emu10k1_ptr_read(emu, *reg, i); } if (emu->audigy) - emu->saved_a_iocfg = inl(emu->port + A_IOCFG); + emu->saved_a_iocfg = inw(emu->port + A_IOCFG); emu->saved_hcfg = inl(emu->port + HCFG); } @@ -2123,7 +1811,7 @@ void snd_emu10k1_resume_init(struct snd_emu10k1 *emu) snd_emu10k1_emu1010_init(emu); else snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); - snd_emu10k1_init(emu, emu->enable_ir, 1); + snd_emu10k1_init(emu, emu->enable_ir); } void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu) @@ -2136,7 +1824,7 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu) /* resore for spdif */ if (emu->audigy) - outl(emu->saved_a_iocfg, emu->port + A_IOCFG); + outw(emu->saved_a_iocfg, emu->port + A_IOCFG); outl(emu->saved_hcfg, emu->port + HCFG); val = emu->saved_ptr; diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c index 549013a4a80b..68dfcb24b889 100644 --- a/sound/pci/emu10k1/emu10k1_synth.c +++ b/sound/pci/emu10k1/emu10k1_synth.c @@ -22,7 +22,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev) struct snd_emux *emux; struct snd_emu10k1 *hw; struct snd_emu10k1_synth_arg *arg; - unsigned long flags; arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); if (arg == NULL) @@ -43,7 +42,6 @@ static int snd_emu10k1_synth_probe(struct device *_dev) emux->hw = hw; emux->max_voices = arg->max_voices; emux->num_ports = arg->seq_ports; - emux->pitch_shift = -501; emux->memhdr = hw->memhdr; /* maximum two ports */ emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; @@ -57,10 +55,10 @@ static int snd_emu10k1_synth_probe(struct device *_dev) return -ENOMEM; } - spin_lock_irqsave(&hw->voice_lock, flags); + spin_lock_irq(&hw->voice_lock); hw->synth = emux; hw->get_synth_voice = snd_emu10k1_synth_get_voice; - spin_unlock_irqrestore(&hw->voice_lock, flags); + spin_unlock_irq(&hw->voice_lock); dev->driver_data = emux; @@ -72,7 +70,6 @@ static int snd_emu10k1_synth_remove(struct device *_dev) struct snd_seq_device *dev = to_seq_dev(_dev); struct snd_emux *emux; struct snd_emu10k1 *hw; - unsigned long flags; if (dev->driver_data == NULL) return 0; /* not registered actually */ @@ -80,10 +77,10 @@ static int snd_emu10k1_synth_remove(struct device *_dev) emux = dev->driver_data; hw = emux->hw; - spin_lock_irqsave(&hw->voice_lock, flags); + spin_lock_irq(&hw->voice_lock); hw->synth = NULL; hw->get_synth_voice = NULL; - spin_unlock_irqrestore(&hw->voice_lock, flags); + spin_unlock_irq(&hw->voice_lock); snd_emux_free(emux); return 0; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index def8161cde4c..89043392f3ec 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -31,7 +31,6 @@ MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>"); MODULE_DESCRIPTION("EMU10K1X"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Dell Creative Labs,SB Live!}"); // module parameters (see "Module Parameters") static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -217,7 +216,6 @@ struct emu10k1x { struct pci_dev *pci; unsigned long port; - struct resource *res_port; int irq; unsigned char revision; /* chip revision */ @@ -234,7 +232,7 @@ struct emu10k1x { struct emu10k1x_voice capture_voice; u32 spdif_bits[3]; // SPDIF out setup - struct snd_dma_buffer dma_buffer; + struct snd_dma_buffer *dma_buffer; struct emu10k1x_midi midi; }; @@ -350,7 +348,8 @@ static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voi { struct emu10k1x_pcm *epcm; - if ((epcm = voice->epcm) == NULL) + epcm = voice->epcm; + if (!epcm) return; if (epcm->substream == NULL) return; @@ -372,10 +371,11 @@ static int snd_emu10k1x_playback_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; - } - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) return err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); @@ -441,7 +441,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct emu10k1x_pcm *epcm = runtime->private_data; int voice = epcm->voice->number; - u32 *table_base = (u32 *)(emu->dma_buffer.area+1024*voice); + u32 *table_base = (u32 *)(emu->dma_buffer->area+1024*voice); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; @@ -450,7 +450,7 @@ static int snd_emu10k1x_pcm_prepare(struct snd_pcm_substream *substream) *table_base++=period_size_bytes<<16; } - snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_ADDR, voice, emu->dma_buffer.addr+1024*voice); + snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_ADDR, voice, emu->dma_buffer->addr+1024*voice); snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_SIZE, voice, (runtime->periods - 1) << 19); snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_PTR, voice, 0); snd_emu10k1x_ptr_write(emu, PLAYBACK_POINTER, voice, 0); @@ -551,10 +551,12 @@ static int snd_emu10k1x_pcm_open_capture(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; int err; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) - return err; - if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) - return err; + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) + return err; + err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64); + if (err < 0) + return err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -723,7 +725,8 @@ static int snd_emu10k1x_ac97(struct emu10k1x *chip) .read = snd_emu10k1x_ac97_read, }; - if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ @@ -733,37 +736,15 @@ static int snd_emu10k1x_ac97(struct emu10k1x *chip) return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } -static int snd_emu10k1x_free(struct emu10k1x *chip) +static void snd_emu10k1x_free(struct snd_card *card) { + struct emu10k1x *chip = card->private_data; + snd_emu10k1x_ptr_write(chip, TRIGGER_CHANNEL, 0, 0); // disable interrupts outl(0, chip->port + INTE); // disable audio outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); - - /* release the irq */ - if (chip->irq >= 0) - free_irq(chip->irq, chip); - - // release the i/o port - release_and_free_resource(chip->res_port); - - // release the DMA - if (chip->dma_buffer.area) { - snd_dma_free_pages(&chip->dma_buffer); - } - - pci_disable_device(chip->pci); - - // release the data - kfree(chip); - return 0; -} - -static int snd_emu10k1x_dev_free(struct snd_device *device) -{ - struct emu10k1x *chip = device->device_data; - return snd_emu10k1x_free(chip); } static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id) @@ -839,7 +820,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) if (device == 0) capture = 1; - if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -880,33 +862,21 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device) } static int snd_emu10k1x_create(struct snd_card *card, - struct pci_dev *pci, - struct emu10k1x **rchip) + struct pci_dev *pci) { - struct emu10k1x *chip; + struct emu10k1x *chip = card->private_data; int err; int ch; - static const struct snd_device_ops ops = { - .dev_free = snd_emu10k1x_dev_free, - }; - - *rchip = NULL; - if ((err = pci_enable_device(pci)) < 0) + err = pcim_enable_device(pci); + if (err < 0) return err; - if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { + + if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(28)) < 0) { dev_err(card->dev, "error to set 28bit mask DMA\n"); - pci_disable_device(pci); return -ENXIO; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) { - pci_disable_device(pci); - return -ENOMEM; - } - chip->card = card; chip->pci = pci; chip->irq = -1; @@ -914,29 +884,24 @@ static int snd_emu10k1x_create(struct snd_card *card, spin_lock_init(&chip->emu_lock); spin_lock_init(&chip->voice_lock); + err = pci_request_regions(pci, "EMU10K1X"); + if (err < 0) + return err; chip->port = pci_resource_start(pci, 0); - if ((chip->res_port = request_region(chip->port, 8, - "EMU10K1X")) == NULL) { - dev_err(card->dev, "cannot allocate the port 0x%lx\n", - chip->port); - snd_emu10k1x_free(chip); - return -EBUSY; - } - if (request_irq(pci->irq, snd_emu10k1x_interrupt, - IRQF_SHARED, KBUILD_MODNAME, chip)) { + if (devm_request_irq(&pci->dev, pci->irq, snd_emu10k1x_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "cannot grab irq %d\n", pci->irq); - snd_emu10k1x_free(chip); return -EBUSY; } chip->irq = pci->irq; card->sync_irq = chip->irq; + card->private_free = snd_emu10k1x_free; - if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, - 4 * 1024, &chip->dma_buffer) < 0) { - snd_emu10k1x_free(chip); + chip->dma_buffer = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, + 4 * 1024); + if (!chip->dma_buffer) return -ENOMEM; - } pci_set_master(pci); /* read revision & serial */ @@ -992,12 +957,6 @@ static int snd_emu10k1x_create(struct snd_card *card, outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, - chip, &ops)) < 0) { - snd_emu10k1x_free(chip); - return err; - } - *rchip = chip; return 0; } @@ -1172,17 +1131,23 @@ static int snd_emu10k1x_mixer(struct emu10k1x *emu) struct snd_kcontrol *kctl; struct snd_card *card = emu->card; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; return 0; @@ -1489,7 +1454,8 @@ static int emu10k1x_midi_init(struct emu10k1x *emu, struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi); + if (err < 0) return err; midi->emu = emu; spin_lock_init(&midi->open_lock); @@ -1512,7 +1478,8 @@ static int snd_emu10k1x_midi(struct emu10k1x *emu) struct emu10k1x_midi *midi = &emu->midi; int err; - if ((err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)")) < 0) + err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -1524,8 +1491,8 @@ static int snd_emu10k1x_midi(struct emu10k1x *emu) return 0; } -static int snd_emu10k1x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int __snd_emu10k1x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1539,43 +1506,37 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, - 0, &card); + err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(*chip), &card); if (err < 0) return err; + chip = card->private_data; - if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_create(card, pci); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_pcm(chip, 0); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_pcm(chip, 1); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_pcm(chip, 2); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_ac97(chip)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_ac97(chip); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_mixer(chip)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_mixer(chip); + if (err < 0) return err; - } - if ((err = snd_emu10k1x_midi(chip)) < 0) { - snd_card_free(card); + err = snd_emu10k1x_midi(chip); + if (err < 0) return err; - } snd_emu10k1x_proc_init(chip); @@ -1584,19 +1545,19 @@ static int snd_emu10k1x_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); + err = snd_card_register(card); + if (err < 0) return err; - } pci_set_drvdata(pci, card); dev++; return 0; } -static void snd_emu10k1x_remove(struct pci_dev *pci) +static int snd_emu10k1x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { - snd_card_free(pci_get_drvdata(pci)); + return snd_card_free_on_error(&pci->dev, __snd_emu10k1x_probe(pci, pci_id)); } // PCI IDs @@ -1611,7 +1572,6 @@ static struct pci_driver emu10k1x_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, - .remove = snd_emu10k1x_remove, }; module_pci_driver(emu10k1x_driver); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 4e76ed0e91d5..03efc317e05f 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1,17 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for effect processor FX8010 - * - * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> - * Added EMU 1010 support. - * - * BUGS: - * -- * - * TODO: - * -- + * Routines for effect processor FX8010 */ #include <linux/pci.h> @@ -46,26 +40,45 @@ MODULE_PARM_DESC(high_res_gpr_volume, "GPR mixer controls use 31-bit range."); * Tables */ -static const char * const fxbuses[16] = { +// Playback channel labels; corresponds with the public FXBUS_* defines. +// Unlike the tables below, this is not determined by the hardware. +const char * const snd_emu10k1_fxbus[32] = { /* 0x00 */ "PCM Left", /* 0x01 */ "PCM Right", - /* 0x02 */ "PCM Surround Left", - /* 0x03 */ "PCM Surround Right", + /* 0x02 */ "PCM Rear Left", + /* 0x03 */ "PCM Rear Right", /* 0x04 */ "MIDI Left", /* 0x05 */ "MIDI Right", - /* 0x06 */ "Center", - /* 0x07 */ "LFE", - /* 0x08 */ NULL, - /* 0x09 */ NULL, + /* 0x06 */ "PCM Center", + /* 0x07 */ "PCM LFE", + /* 0x08 */ "PCM Front Left", + /* 0x09 */ "PCM Front Right", /* 0x0a */ NULL, /* 0x0b */ NULL, /* 0x0c */ "MIDI Reverb", /* 0x0d */ "MIDI Chorus", - /* 0x0e */ NULL, - /* 0x0f */ NULL + /* 0x0e */ "PCM Side Left", + /* 0x0f */ "PCM Side Right", + /* 0x10 */ NULL, + /* 0x11 */ NULL, + /* 0x12 */ NULL, + /* 0x13 */ NULL, + /* 0x14 */ "Passthrough Left", + /* 0x15 */ "Passthrough Right", + /* 0x16 */ NULL, + /* 0x17 */ NULL, + /* 0x18 */ NULL, + /* 0x19 */ NULL, + /* 0x1a */ NULL, + /* 0x1b */ NULL, + /* 0x1c */ NULL, + /* 0x1d */ NULL, + /* 0x1e */ NULL, + /* 0x1f */ NULL }; -static const char * const creative_ins[16] = { +// Physical inputs; corresponds with the public EXTIN_* defines. +const char * const snd_emu10k1_sblive_ins[16] = { /* 0x00 */ "AC97 Left", /* 0x01 */ "AC97 Right", /* 0x02 */ "TTL IEC958 Left", @@ -84,7 +97,8 @@ static const char * const creative_ins[16] = { /* 0x0f */ NULL }; -static const char * const audigy_ins[16] = { +// Physical inputs; corresponds with the public A_EXTIN_* defines. +const char * const snd_emu10k1_audigy_ins[16] = { /* 0x00 */ "AC97 Left", /* 0x01 */ "AC97 Right", /* 0x02 */ "Audigy CD Left", @@ -103,7 +117,8 @@ static const char * const audigy_ins[16] = { /* 0x0f */ NULL }; -static const char * const creative_outs[32] = { +// Physical outputs; corresponds with the public EXTOUT_* defines. +const char * const snd_emu10k1_sblive_outs[32] = { /* 0x00 */ "AC97 Left", /* 0x01 */ "AC97 Right", /* 0x02 */ "Optical IEC958 Left", @@ -120,6 +135,7 @@ static const char * const creative_outs[32] = { /* 0x0d */ "AC97 Surround Left", /* 0x0e */ "AC97 Surround Right", /* 0x0f */ NULL, + // This is actually the FXBUS2 range; SB Live! 5.1 only. /* 0x10 */ NULL, /* 0x11 */ "Analog Center", /* 0x12 */ "Analog LFE", @@ -138,7 +154,8 @@ static const char * const creative_outs[32] = { /* 0x1f */ NULL, }; -static const char * const audigy_outs[32] = { +// Physical outputs; corresponds with the public A_EXTOUT_* defines. +const char * const snd_emu10k1_audigy_outs[32] = { /* 0x00 */ "Digital Front Left", /* 0x01 */ "Digital Front Right", /* 0x02 */ "Digital Center", @@ -173,6 +190,18 @@ static const char * const audigy_outs[32] = { /* 0x1f */ NULL, }; +// On the SB Live! 5.1, FXBUS2[1] and FXBUS2[2] are occupied by EXTOUT_ACENTER +// and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording. +// +// Since only 14 of the 16 EXTINs are used, this is not a big problem. +// We route AC97 to FX capture 14 and 15, SPDIF_CD to FX capture 0 and 3, +// and the rest of the EXTINs to the corresponding FX capture channel. +// Multitrack recorders will still see the center/LFE output signal +// on the second and third "input" channel. +const s8 snd_emu10k1_sblive51_fxbus2_map[16] = { + 2, -1, -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1 +}; + static const u32 bass_table[41][5] = { { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, @@ -318,16 +347,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 +361,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 +378,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 +410,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; } @@ -436,7 +465,8 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, unsigned long flags; spin_lock_irqsave(&emu->fx8010.irq_lock, flags); - if ((tmp = emu->fx8010.irq_handlers) == irq) { + tmp = emu->fx8010.irq_handlers; + if (tmp == irq) { emu->fx8010.irq_handlers = tmp->next; if (emu->fx8010.irq_handlers == NULL) { snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); @@ -640,8 +670,8 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, list_for_each_entry(ctl, &emu->fx8010.gpr_ctl, list) { kcontrol = ctl->kcontrol; if (kcontrol->id.iface == id->iface && - !strcmp(kcontrol->id.name, id->name) && - kcontrol->id.index == id->index) + kcontrol->id.index == id->index && + !strcmp(kcontrol->id.name, id->name)) return ctl; } return NULL; @@ -763,18 +793,43 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, if (snd_emu10k1_look_for_ctl(emu, &gctl->id)) continue; gctl_id = (struct snd_ctl_elem_id *)&gctl->id; - down_read(&emu->card->controls_rwsem); if (snd_ctl_find_id(emu->card, gctl_id)) { - up_read(&emu->card->controls_rwsem); err = -EEXIST; goto __error; } - up_read(&emu->card->controls_rwsem); if (gctl_id->iface != SNDRV_CTL_ELEM_IFACE_MIXER && gctl_id->iface != SNDRV_CTL_ELEM_IFACE_PCM) { 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 */ @@ -871,7 +926,9 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, } knew.private_value = (unsigned long)ctl; *ctl = *nctl; - if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { + kctl = snd_ctl_new1(&knew, emu); + err = snd_ctl_add(emu->card, kctl); + if (err < 0) { kfree(ctl); kfree(knew.tlv.p); goto __error; @@ -911,11 +968,9 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu, in_kernel); if (err < 0) return err; - down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); if (ctl) snd_ctl_remove(card, ctl->kcontrol); - up_write(&card->controls_rwsem); } return 0; } @@ -940,7 +995,7 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu, memset(gctl, 0, sizeof(*gctl)); id = &ctl->kcontrol->id; gctl->id.iface = (__force int)id->iface; - strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name)); + strscpy(gctl->id.name, id->name, sizeof(gctl->id.name)); gctl->id.index = id->index; gctl->id.device = id->device; gctl->id.subdevice = id->subdevice; @@ -976,7 +1031,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu, err = snd_emu10k1_verify_controls(emu, icode, in_kernel); if (err < 0) goto __error; - strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); + strscpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); /* stop FX processor - this may be dangerous, but it's better to miss some samples than generate wrong ones - [jk] */ if (emu->audigy) @@ -1015,7 +1070,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu, int err; mutex_lock(&emu->fx8010.lock); - strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); + strscpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ err = snd_emu10k1_gpr_peek(emu, icode); if (err >= 0) @@ -1113,48 +1168,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, @@ -1184,39 +1247,54 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl } /* - * Used for emu1010 - conversion from 32-bit capture inputs from HANA - * to 2 x 16-bit registers in audigy - their values are read via DMA. + * Used for emu1010 - conversion from 32-bit capture inputs from the FPGA + * 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, i, 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; @@ -1242,57 +1320,48 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) icode->code = icode->tram_addr_map + 256; /* clear free GPRs */ - for (i = 0; i < 512; i++) - set_bit(i, icode->gpr_valid); + memset(icode->gpr_valid, 0xff, 512 / 8); /* clear TRAM data & address lines */ - for (i = 0; i < 256; i++) - set_bit(i, icode->tram_valid); + memset(icode->tram_valid, 0xff, 256 / 8); 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; - - /* stop FX processor */ - snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); + 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++; @@ -1300,159 +1369,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)) - /* emu1212 DSP 0 and DSP 1 Capture */ 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), 0xcd, 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), 0xcd, 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, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), A_C_40000000, A_GPR(stereo_mix+1)); + 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; } @@ -1477,18 +1561,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"); @@ -1507,36 +1579,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); @@ -1545,208 +1620,109 @@ 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); #endif if (emu->card_capabilities->emu_model) { + /* Capture 16 channels of S32_LE sound. */ if (emu->card_capabilities->ca0108_chip) { dev_info(emu->card->dev, "EMU2 inputs on\n"); - for (z = 0; z < 0x10; z++) { + /* Note that the Tina[2] DSPs have 16 more EMU32 inputs which we don't use. */ + + 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"); - /* Capture 16 (originally 8) channels of S32_LE sound */ + /* Note that the Alice2 DSPs have 6 I2S inputs which we don't use. */ /* 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 @@ -1770,11 +1746,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); @@ -1799,30 +1776,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) \ @@ -1834,7 +1795,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) \ @@ -1850,7 +1811,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; @@ -1883,41 +1844,36 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) icode->code = icode->tram_addr_map + 160; /* clear free GPRs */ - for (i = 0; i < 256; i++) - set_bit(i, icode->gpr_valid); + memset(icode->gpr_valid, 0xff, 256 / 8); /* clear TRAM data & address lines */ - for (i = 0; i < 160; i++) - set_bit(i, icode->tram_valid); + memset(icode->tram_valid, 0xff, 160 / 8); strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela"); ptr = 0; i = 0; /* 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 */ - /* stop FX processor */ - snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP); - /* * 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; @@ -2011,7 +1967,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); @@ -2202,13 +2158,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"); @@ -2240,12 +2189,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)); @@ -2267,20 +2223,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 */ @@ -2288,7 +2235,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))) { @@ -2297,7 +2244,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); @@ -2312,9 +2259,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); } @@ -2331,29 +2278,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 } @@ -2367,21 +2314,11 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) /* EFX capture - capture the 16 EXTINS */ if (emu->card_capabilities->sblive51) { - /* On the Live! 5.1, FXBUS2(1) and FXBUS(2) are shared with EXTOUT_ACENTER - * and EXTOUT_ALFE, so we can't connect inputs to them for multitrack recording. - * - * Since only 14 of the 16 EXTINs are used, this is not a big problem. - * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture - * 0 and 3, then the rest of the EXTINs to the corresponding FX capture - * channel. Multitrack recorders will still see the center/lfe output signal - * on the second and third channels. - */ - OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); - OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); - OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); - OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); - for (z = 4; z < 14; z++) - OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); + for (z = 0; z < 16; z++) { + s8 c = snd_emu10k1_sblive51_fxbus2_map[z]; + if (c != -1) + OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(c)); + } } else { for (z = 0; z < 16; z++) OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); @@ -2403,7 +2340,8 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) while (ptr < 0x200) OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000); - if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0) + err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size); + if (err < 0) goto __err; icode->gpr_add_control_count = i; icode->gpr_add_controls = controls; @@ -2480,7 +2418,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size) outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); spin_unlock_irq(&emu->emu_lock); snd_emu10k1_ptr_write(emu, TCB, 0, 0); - snd_emu10k1_ptr_write(emu, TCBS, 0, 0); + snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); if (emu->fx8010.etram_pages.area != NULL) { snd_dma_free_pages(&emu->fx8010.etram_pages); emu->fx8010.etram_pages.area = NULL; @@ -2519,19 +2457,18 @@ static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu, struct snd_emu10k1_fx8010_info *info) { const char * const *fxbus, * const *extin, * const *extout; - unsigned short fxbus_mask, extin_mask, extout_mask; + unsigned short extin_mask, extout_mask; int res; info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; - fxbus = fxbuses; - extin = emu->audigy ? audigy_ins : creative_ins; - extout = emu->audigy ? audigy_outs : creative_outs; - fxbus_mask = emu->fx8010.fxbus_mask; - extin_mask = emu->fx8010.extin_mask; - extout_mask = emu->fx8010.extout_mask; + fxbus = snd_emu10k1_fxbus; + extin = emu->audigy ? snd_emu10k1_audigy_ins : snd_emu10k1_sblive_ins; + extout = emu->audigy ? snd_emu10k1_audigy_outs : snd_emu10k1_sblive_outs; + extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask; + extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask; for (res = 0; res < 16; res++, fxbus++, extin++, extout++) { - copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res); + copy_string(info->fxbus_names[res], *fxbus, "FXBUS", res); copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res); copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res); } @@ -2647,17 +2584,19 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un return -EPERM; if (get_user(addr, (unsigned int __user *)argp)) return -EFAULT; - if (addr > 0x1ff) - return -EINVAL; - if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr); - else - snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr); - udelay(10); - if (emu->audigy) - snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr); - else - snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr); + if (emu->audigy) { + if (addr > A_DBG_STEP_ADDR) + return -EINVAL; + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP); + udelay(10); + snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_STEP | addr); + } else { + if (addr > EMU10K1_DBG_SINGLE_STEP_ADDR) + return -EINVAL; + snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP); + udelay(10); + snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_STEP | addr); + } return 0; case SNDRV_EMU10K1_IOCTL_DBG_READ: if (emu->audigy) @@ -2681,7 +2620,8 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device) struct snd_hwdep *hw; int err; - if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0) + err = snd_hwdep_new(emu->card, "FX8010", device, &hw); + if (err < 0) return err; strcpy(hw->name, "EMU10K1 (FX8010)"); hw->iface = SNDRV_HWDEP_IFACE_EMU10K1; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 8a6cbe67e29d..0a32ea53d8c6 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -2,18 +2,12 @@ /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, * Takashi Iwai <tiwai@suse.de> + * Lee Revell <rlrevell@joe-job.com> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for control of EMU10K1 chips / mixer routines - * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> - * - * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> - * Added EMU 1010 support. - * - * BUGS: - * -- * - * TODO: - * -- + * Routines for control of EMU10K1 chips / mixer routines */ #include <linux/time.h> @@ -29,6 +23,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 +53,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 +74,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 - HANA outputs going to Alice2 (audigy) for + * 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, @@ -367,6 +438,7 @@ static const unsigned int emu1010_input_dst[] = { EMU_DST_ALICE2_EMU32_D, EMU_DST_ALICE2_EMU32_E, EMU_DST_ALICE2_EMU32_F, + /* These exist only on rev1 EMU1010 cards. */ EMU_DST_ALICE_I2S0_LEFT, EMU_DST_ALICE_I2S0_RIGHT, EMU_DST_ALICE_I2S1_LEFT, @@ -374,29 +446,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; @@ -406,41 +648,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; @@ -450,134 +692,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; } @@ -585,39 +762,48 @@ 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; + int change; + val = ucontrol->value.integer.value[0]; cache = emu->emu1010.adc_pads; if (val == 1) cache = cache | mask; else cache = cache & ~mask; - if (cache != emu->emu1010.adc_pads) { + change = (cache != emu->emu1010.adc_pads); + if (change) { snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); emu->emu1010.adc_pads = cache; } - return 0; + return change; } +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 @@ -625,7 +811,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; } @@ -633,163 +820,241 @@ 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, + }, }; +static const char * const emu1010_clock_texts[] = { + "44100", "48000", "SPDIF", "ADAT", "Dock", "BNC" +}; -static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, +static const u8 emu1010_clock_vals[] = { + EMU_HANA_WCLOCK_INT_44_1K, + EMU_HANA_WCLOCK_INT_48K, + EMU_HANA_WCLOCK_HANA_SPDIF_IN, + EMU_HANA_WCLOCK_HANA_ADAT_IN, + EMU_HANA_WCLOCK_2ND_HANA, + EMU_HANA_WCLOCK_SYNC_BNC, +}; + +static const char * const emu0404_clock_texts[] = { + "44100", "48000", "SPDIF", "BNC" +}; + +static const u8 emu0404_clock_vals[] = { + EMU_HANA_WCLOCK_INT_44_1K, + EMU_HANA_WCLOCK_INT_48K, + EMU_HANA_WCLOCK_HANA_SPDIF_IN, + EMU_HANA_WCLOCK_SYNC_BNC, +}; + +struct snd_emu1010_clock_info { + const char * const *texts; + const u8 *vals; + unsigned num; +}; + +static const struct snd_emu1010_clock_info emu1010_clock_info[] = { + { + // rev1 1010 + .texts = emu1010_clock_texts, + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals), + }, + { + // rev2 1010 + .texts = emu1010_clock_texts, + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals) - 1, + }, + { + // 1616(m) CardBus + .texts = emu1010_clock_texts, + // TODO: determine what is actually available. + // Pedantically, *every* source comes from the 2nd FPGA, as the + // card itself has no own (digital) audio ports. The user manual + // claims that ADAT and S/PDIF clock sources are separate, which + // can mean two things: either E-MU mapped the dock's sources to + // the primary ones, or they determine the meaning of the "Dock" + // source depending on how the ports are actually configured + // (which the 2nd FPGA must be doing anyway). + .vals = emu1010_clock_vals, + .num = ARRAY_SIZE(emu1010_clock_vals), + }, + { + // 0404 + .texts = emu0404_clock_texts, + .vals = emu0404_clock_vals, + .num = ARRAY_SIZE(emu0404_clock_vals), + }, +}; + +static int snd_emu1010_clock_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[4] = { - "44100", "48000", "SPDIF", "ADAT" - }; + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + const struct snd_emu1010_clock_info *emu_ci = + &emu1010_clock_info[emu1010_idx(emu)]; - return snd_ctl_enum_info(uinfo, 1, 4, texts); + return snd_ctl_enum_info(uinfo, 1, emu_ci->num, emu_ci->texts); } -static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, +static int snd_emu1010_clock_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; + ucontrol->value.enumerated.item[0] = emu->emu1010.clock_source; return 0; } -static int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, +static int snd_emu1010_clock_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + const struct snd_emu1010_clock_info *emu_ci = + &emu1010_clock_info[emu1010_idx(emu)]; unsigned int val; int change = 0; val = ucontrol->value.enumerated.item[0] ; - /* Limit: uinfo->value.enumerated.items = 4; */ - if (val >= 4) + if (val >= emu_ci->num) return -EINVAL; - change = (emu->emu1010.internal_clock != val); + spin_lock_irq(&emu->reg_lock); + change = (emu->emu1010.clock_source != val); if (change) { - emu->emu1010.internal_clock = val; - switch (val) { - case 0: - /* 44100 */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); - /* Word Clock source, Internal 44.1kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - case 1: - /* 48000 */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); - /* Word Clock source, Internal 48kHz x1 */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - - case 2: /* Take clock from S/PDIF IN */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); - /* Word Clock source, sync to S/PDIF input */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, - EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - break; - - case 3: - /* Take clock from ADAT IN */ - /* Mute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); - /* Default fallback clock 48kHz */ - snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); - /* Word Clock source, sync to ADAT input */ - snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, - EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); - /* Set LEDs on Audio Dock */ - snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); - /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ - /* Allow DLL to settle */ - msleep(10); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); - - - break; - } + emu->emu1010.clock_source = val; + emu->emu1010.wclock = emu_ci->vals[val]; + snd_emu1010_update_clock(emu); + + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE); + snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, emu->emu1010.wclock); + spin_unlock_irq(&emu->reg_lock); + + msleep(10); // Allow DLL to settle + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + } else { + spin_unlock_irq(&emu->reg_lock); } - return change; + return change; } -static const struct snd_kcontrol_new snd_emu1010_internal_clock = +static const struct snd_kcontrol_new snd_emu1010_clock_source = { - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Clock Internal Rate", - .count = 1, - .info = snd_emu1010_internal_clock_info, - .get = snd_emu1010_internal_clock_get, - .put = snd_emu1010_internal_clock_put + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Source", + .count = 1, + .info = snd_emu1010_clock_source_info, + .get = snd_emu1010_clock_source_get, + .put = snd_emu1010_clock_source_put +}; + +static int snd_emu1010_clock_fallback_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char * const texts[2] = { + "44100", "48000" + }; + + return snd_ctl_enum_info(uinfo, 1, 2, texts); +} + +static int snd_emu1010_clock_fallback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = emu->emu1010.clock_fallback; + return 0; +} + +static int snd_emu1010_clock_fallback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); + unsigned int val = ucontrol->value.enumerated.item[0]; + int change; + + if (val >= 2) + return -EINVAL; + change = (emu->emu1010.clock_fallback != val); + if (change) { + emu->emu1010.clock_fallback = val; + snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 1 - val); + } + return change; +} + +static const struct snd_kcontrol_new snd_emu1010_clock_fallback = +{ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Clock Fallback", + .count = 1, + .info = snd_emu1010_clock_fallback_info, + .get = snd_emu1010_clock_fallback_get, + .put = snd_emu1010_clock_fallback_put }; static int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, @@ -826,8 +1091,8 @@ static int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.optical_out != val); if (change) { emu->emu1010.optical_out = val; - tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | - (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); + 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); } return change; @@ -877,8 +1142,8 @@ static int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, change = (emu->emu1010.optical_in != val); if (change) { emu->emu1010.optical_in = val; - tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | - (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); + 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); } return change; @@ -924,9 +1189,8 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int source_id; unsigned int ngain, ogain; - u32 gpio; + u16 gpio; int change = 0; - unsigned long flags; u32 source; /* If the capture source has changed, * update the capture volume from the cached value @@ -940,13 +1204,13 @@ static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, change = (emu->i2c_capture_source != source_id); if (change) { snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ - spin_lock_irqsave(&emu->emu_lock, flags); - gpio = inl(emu->port + A_IOCFG); + spin_lock_irq(&emu->emu_lock); + gpio = inw(emu->port + A_IOCFG); if (source_id==0) - outl(gpio | 0x4, emu->port + A_IOCFG); + outw(gpio | 0x4, emu->port + A_IOCFG); else - outl(gpio & ~0x4, emu->port + A_IOCFG); - spin_unlock_irqrestore(&emu->emu_lock, flags); + outw(gpio & ~0x4, emu->port + A_IOCFG); + spin_unlock_irq(&emu->emu_lock); ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ @@ -1005,7 +1269,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, { struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int ogain; - unsigned int ngain; + unsigned int ngain0, ngain1; unsigned int source_id; int change = 0; @@ -1014,46 +1278,43 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, /* capture_source: uinfo->value.enumerated.items = 2 */ if (source_id >= 2) return -EINVAL; + ngain0 = ucontrol->value.integer.value[0]; + ngain1 = ucontrol->value.integer.value[1]; + if (ngain0 > 0xff) + return -EINVAL; + if (ngain1 > 0xff) + return -EINVAL; ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ - ngain = ucontrol->value.integer.value[0]; - if (ngain > 0xff) - return 0; - if (ogain != ngain) { + if (ogain != ngain0) { if (emu->i2c_capture_source == source_id) - snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); - emu->i2c_capture_volume[source_id][0] = ngain; + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ngain0); + emu->i2c_capture_volume[source_id][0] = ngain0; change = 1; } ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ - ngain = ucontrol->value.integer.value[1]; - if (ngain > 0xff) - return 0; - if (ogain != ngain) { + if (ogain != ngain1) { if (emu->i2c_capture_source == source_id) - snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); - emu->i2c_capture_volume[source_id][1] = ngain; + snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ngain1); + emu->i2c_capture_volume[source_id][1] = ngain1; change = 1; } 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 @@ -1069,10 +1330,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: @@ -1087,7 +1345,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; } @@ -1097,7 +1354,6 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int change; unsigned int reg, val, tmp; - unsigned long flags; switch(ucontrol->value.enumerated.item[0]) { case 0: @@ -1115,13 +1371,14 @@ static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, } - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp = reg & ~A_SPDIF_RATE_MASK; tmp |= val; - if ((change = (tmp != reg))) + change = (tmp != reg); + if (change) snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1144,7 +1401,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) @@ -1153,13 +1409,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; } @@ -1187,10 +1441,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)); @@ -1204,11 +1458,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)); } } @@ -1227,7 +1478,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)]; @@ -1235,19 +1485,16 @@ 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; } static int snd_emu10k1_send_routing_put(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)]; @@ -1255,7 +1502,7 @@ static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (voice = 0; voice < 3; voice++) for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; @@ -1264,18 +1511,18 @@ 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]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1303,31 +1550,27 @@ 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; } static int snd_emu10k1_send_volume_put(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 change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < 3*num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { @@ -1335,18 +1578,18 @@ 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]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1366,7 +1609,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; } @@ -1376,42 +1619,39 @@ 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; } static int snd_emu10k1_attn_put(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 change = 0, idx, val; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); 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]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1441,7 +1681,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)]; @@ -1449,18 +1688,15 @@ 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; } static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; @@ -1468,7 +1704,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, int num_efx = emu->audigy ? 8 : 4; int mask = emu->audigy ? 0x3f : 0x0f; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & mask; if (mix->send_routing[0][idx] != val) { @@ -1483,7 +1719,7 @@ static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, &mix->send_routing[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1511,31 +1747,27 @@ 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; } static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; int change = 0, idx, val; int num_efx = emu->audigy ? 8 : 4; - spin_lock_irqsave(&emu->reg_lock, flags); + spin_lock_irq(&emu->reg_lock); for (idx = 0; idx < num_efx; idx++) { val = ucontrol->value.integer.value[idx] & 255; if (mix->send_volume[0][idx] != val) { @@ -1549,7 +1781,7 @@ static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, &mix->send_volume[0][0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1570,7 +1802,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; } @@ -1580,25 +1812,23 @@ 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; } static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(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; + spin_lock_irq(&emu->reg_lock); + uval = ucontrol->value.integer.value[0] & 0x1ffff; + val = uval * 0x8000U / 0xffffU; if (mix->attn[0] != val) { mix->attn[0] = val; change = 1; @@ -1608,7 +1838,7 @@ static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); } } - spin_unlock_irqrestore(&emu->reg_lock, flags); + spin_unlock_irq(&emu->reg_lock); return change; } @@ -1631,7 +1861,7 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); if (emu->audigy) - ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; + ucontrol->value.integer.value[0] = inw(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; else ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; if (emu->card_capabilities->invert_shared_spdif) @@ -1644,7 +1874,6 @@ static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - unsigned long flags; struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int reg, val, sw; int change = 0; @@ -1652,17 +1881,17 @@ 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_irq(&emu->emu_lock); if ( emu->card_capabilities->i2c_adc) { /* Do nothing for Audigy 2 ZS Notebook */ } else if (emu->audigy) { - reg = inl(emu->port + A_IOCFG); + reg = inw(emu->port + A_IOCFG); val = sw ? A_IOCFG_GPOUT0 : 0; change = (reg & A_IOCFG_GPOUT0) != val; if (change) { reg &= ~A_IOCFG_GPOUT0; reg |= val; - outl(reg | val, emu->port + A_IOCFG); + outw(reg | val, emu->port + A_IOCFG); } } reg = inl(emu->port + HCFG); @@ -1673,7 +1902,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_irq(&emu->emu_lock); return change; } @@ -1753,20 +1982,11 @@ static int remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) -{ - struct snd_ctl_elem_id sid; - memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, name); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(card, &sid); -} - static int rename_ctl(struct snd_card *card, const char *src, const char *dst) { - struct snd_kcontrol *kctl = ctl_find(card, src); + struct snd_kcontrol *kctl = snd_ctl_find_id_mixer(card, src); if (kctl) { - strcpy(kctl->id.name, dst); + snd_ctl_rename(card, kctl, dst); return 0; } return -ENOENT; @@ -1775,7 +1995,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; @@ -1903,7 +2123,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, .read = snd_emu10k1_ac97_read, }; - if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) + err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus); + if (err < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ @@ -1911,7 +2132,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, ac97.private_data = emu; ac97.private_free = snd_emu10k1_mixer_free_ac97; ac97.scaps = AC97_SCAP_NO_SPDIF; - if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { + err = snd_ac97_mixer(pbus, &ac97, &emu->ac97); + if (err < 0) { if (emu->card_capabilities->ac97_chip == 1) return err; dev_info(emu->card->dev, @@ -1991,222 +2213,162 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); } - if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) + kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) + kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) + kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = pcm_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) + kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) + kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) + kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu); + if (!kctl) return -ENOMEM; kctl->id.device = multi_device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + 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 */ - if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu); + if (!kctl) return -ENOMEM; if (!emu->audigy) kctl->id.device = emu->pcm_efx->device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; - if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu); + if (!kctl) return -ENOMEM; if (!emu->audigy) kctl->id.device = emu->pcm_efx->device; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; } if (emu->card_capabilities->emu_model) { ; /* Disable the snd_audigy_spdif_shared_spdif */ } else if (emu->audigy) { - if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; #if 0 - if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) + kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; #endif } else if (! emu->card_capabilities->ecard) { /* sb live! */ - if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) + kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu); + if (!kctl) return -ENOMEM; - if ((err = snd_ctl_add(card, kctl))) + err = snd_ctl_add(card, kctl); + if (err) return err; } if (emu->card_capabilities->ca0151_chip) { /* P16V */ - if ((err = snd_p16v_mixer(emu))) + err = snd_p16v_mixer(emu); + if (err) return err; } - if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { - /* 1616(m) cardbus */ - int i; - - 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 (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); + + kctl = emu->ctl_clock_source = snd_ctl_new1(&snd_emu1010_clock_source, emu); + err = snd_ctl_add(card, kctl); if (err < 0) return err; err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_out, emu)); + snd_ctl_new1(&snd_emu1010_clock_fallback, emu)); if (err < 0) return err; - err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_optical_in, emu)); + + err = add_ctls(emu, &emu1010_adc_pads_ctl, + emu_pi->adc_ctls, emu_pi->n_adc_ctls); + if (err < 0) + return err; + 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++) { + if (!emu->card_capabilities->no_adat) { err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], - emu)); + snd_ctl_new1(&snd_emu1010_optical_out, 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++) { err = snd_ctl_add(card, - snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); + snd_ctl_new1(&snd_emu1010_optical_in, 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)); - 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/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index b62c95150702..747c34b3d566 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -104,10 +104,9 @@ static void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int st static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack) { - unsigned long flags; int timeout, ok; - spin_lock_irqsave(&midi->input_lock, flags); + spin_lock_irq(&midi->input_lock); mpu401_write_data(emu, midi, 0x00); /* mpu401_clear_rx(emu, midi); */ @@ -126,7 +125,7 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid } else { ok = 1; } - spin_unlock_irqrestore(&midi->input_lock, flags); + spin_unlock_irq(&midi->input_lock); if (!ok) { dev_err(emu->card->dev, "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", @@ -142,22 +141,21 @@ static int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; midi->substream_input = substream; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) goto error_out; if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) goto error_out; } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return 0; @@ -169,22 +167,21 @@ static int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = substream; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1)) goto error_out; if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1)) goto error_out; } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return 0; @@ -196,21 +193,20 @@ static int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream) { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); snd_emu10k1_intr_disable(emu, midi->rx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; midi->substream_input = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return err; } @@ -219,21 +215,20 @@ static int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; int err = 0; emu = midi->emu; if (snd_BUG_ON(!emu)) return -ENXIO; - spin_lock_irqsave(&midi->open_lock, flags); + spin_lock_irq(&midi->open_lock); snd_emu10k1_intr_disable(emu, midi->tx_enable); midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; midi->substream_output = NULL; if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); } else { - spin_unlock_irqrestore(&midi->open_lock, flags); + spin_unlock_irq(&midi->open_lock); } return err; } @@ -256,7 +251,6 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr { struct snd_emu10k1 *emu; struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data; - unsigned long flags; emu = midi->emu; if (snd_BUG_ON(!emu)) @@ -267,13 +261,13 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr unsigned char byte; /* try to send some amount of bytes here before interrupts */ - spin_lock_irqsave(&midi->output_lock, flags); + spin_lock_irq(&midi->output_lock); while (max > 0) { if (mpu401_output_ready(emu, midi)) { if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || snd_rawmidi_transmit(substream, &byte, 1) != 1) { /* no more data */ - spin_unlock_irqrestore(&midi->output_lock, flags); + spin_unlock_irq(&midi->output_lock); return; } mpu401_write_data(emu, midi, byte); @@ -282,7 +276,7 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr break; } } - spin_unlock_irqrestore(&midi->output_lock, flags); + spin_unlock_irq(&midi->output_lock); snd_emu10k1_intr_enable(emu, midi->tx_enable); } else { snd_emu10k1_intr_disable(emu, midi->tx_enable); @@ -319,7 +313,8 @@ static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *m struct snd_rawmidi *rmidi; int err; - if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) + err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi); + if (err < 0) return err; midi->emu = emu; spin_lock_init(&midi->open_lock); @@ -342,7 +337,8 @@ int snd_emu10k1_midi(struct snd_emu10k1 *emu) struct snd_emu10k1_midi *midi = &emu->midi; int err; - if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0) + err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -360,7 +356,8 @@ int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) int err; midi = &emu->midi; - if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0) + err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)"); + if (err < 0) return err; midi->tx_enable = INTE_MIDITXENABLE; @@ -371,7 +368,8 @@ int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) midi->interrupt = snd_emu10k1_midi_interrupt; midi = &emu->midi2; - if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0) + err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2"); + if (err < 0) return err; midi->tx_enable = INTE_A_MIDITXENABLE2; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index b2ddabb99438..7f4c1b38d6ec 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1,15 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * Lee Revell <rlrevell@joe-job.com> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for control of EMU10K1 chips / PCM routines - * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> - * - * BUGS: - * -- * - * TODO: - * -- + * Routines for control of EMU10K1 chips / PCM routines */ #include <linux/pci.h> @@ -25,7 +22,8 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu, { struct snd_emu10k1_pcm *epcm; - if ((epcm = voice->epcm) == NULL) + epcm = voice->epcm; + if (!epcm) return; if (epcm->substream == NULL) return; @@ -75,82 +73,64 @@ static void snd_emu10k1_pcm_efx_interrupt(struct snd_emu10k1 *emu, snd_pcm_period_elapsed(emu->pcm_capture_efx_substream); } -static snd_pcm_uframes_t snd_emu10k1_efx_playback_pointer(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 ptr; - - if (!epcm->running) - return 0; - ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; - ptr += runtime->buffer_size; - ptr -= epcm->ccca_start_addr; - ptr %= runtime->buffer_size; - - return ptr; -} - -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]; - 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, @@ -161,9 +141,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 }; @@ -194,12 +174,22 @@ static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) } } +static const unsigned int audigy_capture_rates[9] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + +static const struct snd_pcm_hw_constraint_list hw_constraints_audigy_capture_rates = { + .count = 9, + .list = audigy_capture_rates, + .mask = 0 +}; + static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) { switch (rate) { case 8000: return A_ADCCR_SAMPLERATE_8; case 11025: return A_ADCCR_SAMPLERATE_11; - case 12000: return A_ADCCR_SAMPLERATE_12; /* really supported? */ + case 12000: return A_ADCCR_SAMPLERATE_12; case 16000: return ADCCR_SAMPLERATE_16; case 22050: return ADCCR_SAMPLERATE_22; case 24000: return ADCCR_SAMPLERATE_24; @@ -212,6 +202,34 @@ static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) } } +static void snd_emu10k1_constrain_capture_rates(struct snd_emu10k1 *emu, + struct snd_pcm_runtime *runtime) +{ + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) { + // This also sets the rate constraint by deleting SNDRV_PCM_RATE_KNOT + runtime->hw.rates = SNDRV_PCM_RATE_11025 | \ + SNDRV_PCM_RATE_22050 | \ + SNDRV_PCM_RATE_44100; + runtime->hw.rate_min = 11025; + runtime->hw.rate_max = 44100; + return; + } + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + emu->audigy ? &hw_constraints_audigy_capture_rates : + &hw_constraints_capture_rates); +} + +static void snd_emu1010_constrain_efx_rate(struct snd_emu10k1 *emu, + struct snd_pcm_runtime *runtime) +{ + int rate; + + rate = emu->emu1010.word_clock; + runtime->hw.rate_min = runtime->hw.rate_max = rate; + runtime->hw.rates = snd_pcm_rate_to_rate_bit(rate); +} + static unsigned int emu10k1_calc_pitch_target(unsigned int rate) { unsigned int pitch_target; @@ -248,146 +266,105 @@ 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 pitch_target; - unsigned int ccis; + unsigned int silent_page; + int voice; 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; + 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(evoice->epcm->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 { + snd_emu10k1_ptr_write(emu, FXRT, voice, + snd_emu10k1_compose_send_routing(send_routing)); } - spin_lock_irqsave(&emu->reg_lock, flags); + emu->voices[voice].dirty = 1; +} - /* 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)); - } 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); - } +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) +{ + spin_lock_irq(&emu->reg_lock); + 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_irq(&emu->reg_lock); +} - 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); - } - } +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 }; - /* 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)); - /* Stop CA */ - /* 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, CVCF, voice, 0xffff); - snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); - 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); - - spin_unlock_irqrestore(&emu->reg_lock, flags); + 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, @@ -397,9 +374,20 @@ 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; - if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) + 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; alloc_size = params_buffer_bytes(hw_params); @@ -439,43 +427,7 @@ static int snd_emu10k1_playback_hw_free(struct snd_pcm_substream *substream) snd_emu10k1_voice_free(epcm->emu, epcm->extra); epcm->extra = NULL; } - if (epcm->voices[1]) { - snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); - epcm->voices[1] = NULL; - } - if (epcm->voices[0]) { - snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]); - epcm->voices[0] = NULL; - } - if (epcm->memblk) { - snd_emu10k1_free_pages(emu, epcm->memblk); - epcm->memblk = NULL; - epcm->start_addr = 0; - } - snd_pcm_lib_free_pages(substream); - return 0; -} - -static int snd_emu10k1_efx_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; - epcm = runtime->private_data; - if (epcm->extra) { - 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; @@ -490,26 +442,28 @@ 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; + unsigned int rate; + + rate = runtime->rate; + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) + rate = rate * 480 / 441; + epcm->pitch_target = emu10k1_calc_pitch_target(rate); + + 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]); - 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]); return 0; } @@ -518,31 +472,25 @@ 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; + unsigned int start_addr; + unsigned int extra_size, channel_size; + unsigned int i; - start_addr = epcm->start_addr; - end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); + epcm->pitch_target = PITCH_48000; - /* - * the kX driver leaves some space between voices - */ - channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK; - - snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, - start_addr, start_addr + (channel_size / 2), NULL); - - /* 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]); - - 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]); + start_addr = epcm->start_addr >> 1; // 16-bit voices + + extra_size = runtime->period_size; + channel_size = runtime->buffer_size; + + snd_emu10k1_pcm_init_extra_voice(emu, epcm->extra, true, + start_addr, start_addr + extra_size); + + 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; } @@ -559,13 +507,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, }; @@ -583,9 +530,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; @@ -596,7 +551,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; } @@ -606,132 +561,181 @@ static int snd_emu10k1_capture_prepare(struct snd_pcm_substream *substream) epcm->capture_bs_val++; } if (epcm->type == CAPTURE_AC97ADC) { + unsigned rate = runtime->rate; + if (!(runtime->hw.rates & SNDRV_PCM_RATE_48000)) + rate = rate * 480 / 441; + epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE; if (runtime->channels > 1) epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE; epcm->capture_cr_val |= emu->audigy ? - snd_emu10k1_audigy_capture_rate_reg(runtime->rate) : - snd_emu10k1_capture_rate_reg(runtime->rate); + snd_emu10k1_audigy_capture_rate_reg(rate) : + snd_emu10k1_capture_rate_reg(rate); } 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 | 0xffff); - snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | 0xffff); - 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) { - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - unsigned int voice, pitch, pitch_target; + snd_emu10k1_playback_unmute_voice(emu, evoice, stereo, true, mix); + if (stereo) + snd_emu10k1_playback_unmute_voice(emu, evoice + 1, true, false, mix); +} - if (evoice == NULL) /* skip second voice for mono */ - return; - substream = evoice->epcm->substream; - runtime = substream->runtime; - voice = evoice->number; +static void snd_emu10k1_playback_mute_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) +{ + snd_emu10k1_playback_commit_volume(emu, evoice, 0); +} - 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); +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_stop_voice(struct snd_emu10k1 *emu, struct snd_emu10k1_voice *evoice) +static void snd_emu10k1_playback_trigger_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, 0xffff); - snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); - snd_emu10k1_ptr_write(emu, IP, voice, 0); + snd_emu10k1_playback_commit_pitch(emu, voice, evoice->epcm->pitch_target << 16); } -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_stop_voice(struct snd_emu10k1 *emu, + struct snd_emu10k1_voice *evoice) { - unsigned int ptr, period_pos; + unsigned int voice; - /* 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); + voice = evoice->number; + snd_emu10k1_playback_commit_pitch(emu, voice, 0); +} + +static void snd_emu10k1_playback_set_running(struct snd_emu10k1 *emu, + struct snd_emu10k1_pcm *epcm) +{ + epcm->running = 1; + snd_emu10k1_voice_intr_enable(emu, epcm->extra->number); +} + +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, @@ -741,6 +745,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; /* @@ -751,29 +757,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; @@ -808,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, 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, @@ -836,8 +838,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; @@ -857,24 +861,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", @@ -884,6 +891,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) @@ -891,45 +941,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; } @@ -969,9 +1036,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, }; @@ -987,7 +1053,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, @@ -1007,13 +1073,11 @@ static const struct snd_pcm_hardware snd_emu10k1_capture_efx = SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, - .rate_min = 44100, - .rate_max = 192000, - .channels_min = 8, - .channels_max = 8, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 16, .buffer_bytes_max = (64*1024), .period_bytes_min = 384, .period_bytes_max = (64*1024), @@ -1074,13 +1138,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) @@ -1089,18 +1169,24 @@ static int snd_emu10k1_efx_playback_open(struct snd_pcm_substream *substream) epcm->type = PLAYBACK_EFX; epcm->substream = substream; - emu->pcm_playback_efx_substream = substream; - runtime->private_data = epcm; runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_efx_playback; - + if (emu->card_capabilities->emu_model) + snd_emu1010_constrain_efx_rate(emu, runtime); + 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); } @@ -1124,16 +1210,13 @@ 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; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { - kfree(epcm); - return err; - } - if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) { + err = snd_emu10k1_playback_set_constraints(runtime); + if (err < 0) { kfree(epcm); return err; } - if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0) - sample_rate = 44100; + if (emu->card_capabilities->emu_model) + sample_rate = emu->emu1010.word_clock; else sample_rate = 48000; err = snd_pcm_hw_rule_noresample(runtime, sample_rate); @@ -1142,12 +1225,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; @@ -1183,10 +1266,11 @@ 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_emu10k1_constrain_capture_rates(emu, runtime); + 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; } @@ -1221,10 +1305,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; } @@ -1232,7 +1316,7 @@ static int snd_emu10k1_capture_mic_close(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - emu->capture_interrupt = NULL; + emu->capture_mic_interrupt = NULL; emu->pcm_capture_mic_substream = NULL; return 0; } @@ -1243,7 +1327,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) @@ -1259,66 +1343,30 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream) substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_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) { - /* Nb. of channels has been increased to 16 */ - /* TODO - * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE - * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - * 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 - * + snd_emu1010_constrain_efx_rate(emu, runtime); + /* * There are 32 mono channels of 16bits each. - * 24bit Audio uses 2x channels over 16bit - * 96kHz uses 2x channels over 48kHz - * 192kHz uses 4x channels over 48kHz - * So, for 48kHz 24bit, one has 16 channels - * for 96kHz 24bit, one has 8 channels - * for 192kHz 24bit, one has 4 channels - * + * 24bit Audio uses 2x channels over 16bit, + * 96kHz uses 2x channels over 48kHz, + * 192kHz uses 4x channels over 48kHz. + * So, for 48kHz 24bit, one has 16 channels, + * for 96kHz 24bit, one has 8 channels, + * for 192kHz 24bit, one has 4 channels. + * 1010rev2 and 1616(m) cards have double that, + * but we don't exceed 16 channels anyway. */ -#if 1 - switch (emu->emu1010.internal_clock) { - case 0: - /* 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 #if 0 /* For 96kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_96000; - runtime->hw.rate_min = runtime->hw.rate_max = 96000; runtime->hw.channels_min = runtime->hw.channels_max = 4; #endif #if 0 /* For 192kHz */ - runtime->hw.rates = SNDRV_PCM_RATE_192000; - runtime->hw.rate_min = runtime->hw.rate_max = 192000; 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))) { @@ -1326,13 +1374,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; } @@ -1340,7 +1395,7 @@ static int snd_emu10k1_capture_efx_close(struct snd_pcm_substream *substream) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - emu->capture_interrupt = NULL; + emu->capture_efx_interrupt = NULL; emu->pcm_capture_efx_substream = NULL; return 0; } @@ -1368,10 +1423,10 @@ static const struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .open = snd_emu10k1_efx_playback_open, .close = snd_emu10k1_efx_playback_close, .hw_params = snd_emu10k1_playback_hw_params, - .hw_free = snd_emu10k1_efx_playback_hw_free, + .hw_free = snd_emu10k1_playback_hw_free, .prepare = snd_emu10k1_efx_playback_prepare, .trigger = snd_emu10k1_efx_playback_trigger, - .pointer = snd_emu10k1_efx_playback_pointer, + .pointer = snd_emu10k1_playback_pointer, }; int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) @@ -1380,7 +1435,8 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1412,7 +1468,8 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device) struct snd_pcm_substream *substream; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1446,7 +1503,8 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device) struct snd_pcm *pcm; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -1480,10 +1538,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; } @@ -1492,7 +1548,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; @@ -1501,12 +1556,8 @@ static int snd_emu10k1_pcm_efx_voices_mask_put(struct snd_kcontrol *kcontrol, st nval[idx / 32] |= 1 << (idx % 32); bits++; } - - 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); @@ -1638,12 +1689,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; @@ -1774,50 +1827,46 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device) struct snd_kcontrol *kctl; int err; - if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) + err = snd_pcm_new(emu->card, "emu10k1 efx", device, emu->audigy ? 0 : 8, 1, &pcm); + if (err < 0) return err; pcm->private_data = emu; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); + if (!emu->audigy) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops); pcm->info_flags = 0; - strcpy(pcm->name, "Multichannel Capture/PT Playback"); + if (emu->audigy) + strcpy(pcm->name, "Multichannel Capture"); + else + 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 - */ - - /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ - 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 6e20cca9c98f..2f80fd91017c 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -1,17 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * Lee Revell <rlrevell@joe-job.com> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for control of EMU10K1 chips / proc interface routines - * - * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> - * Added EMU 1010 support. * - * BUGS: - * -- - * - * TODO: - * -- + * Routines for control of EMU10K1 chips / proc interface routines */ #include <linux/slab.h> @@ -66,158 +61,100 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu, static void snd_emu10k1_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - /* FIXME - output names are in emufx.c too */ - static const char * const creative_outs[32] = { - /* 00 */ "AC97 Left", - /* 01 */ "AC97 Right", - /* 02 */ "Optical IEC958 Left", - /* 03 */ "Optical IEC958 Right", - /* 04 */ "Center", - /* 05 */ "LFE", - /* 06 */ "Headphone Left", - /* 07 */ "Headphone Right", - /* 08 */ "Surround Left", - /* 09 */ "Surround Right", - /* 10 */ "PCM Capture Left", - /* 11 */ "PCM Capture Right", - /* 12 */ "MIC Capture", - /* 13 */ "AC97 Surround Left", - /* 14 */ "AC97 Surround Right", - /* 15 */ "???", - /* 16 */ "???", - /* 17 */ "Analog Center", - /* 18 */ "Analog LFE", - /* 19 */ "???", - /* 20 */ "???", - /* 21 */ "???", - /* 22 */ "???", - /* 23 */ "???", - /* 24 */ "???", - /* 25 */ "???", - /* 26 */ "???", - /* 27 */ "???", - /* 28 */ "???", - /* 29 */ "???", - /* 30 */ "???", - /* 31 */ "???" - }; - - static const char * const audigy_outs[64] = { - /* 00 */ "Digital Front Left", - /* 01 */ "Digital Front Right", - /* 02 */ "Digital Center", - /* 03 */ "Digital LEF", - /* 04 */ "Headphone Left", - /* 05 */ "Headphone Right", - /* 06 */ "Digital Rear Left", - /* 07 */ "Digital Rear Right", - /* 08 */ "Front Left", - /* 09 */ "Front Right", - /* 10 */ "Center", - /* 11 */ "LFE", - /* 12 */ "???", - /* 13 */ "???", - /* 14 */ "Rear Left", - /* 15 */ "Rear Right", - /* 16 */ "AC97 Front Left", - /* 17 */ "AC97 Front Right", - /* 18 */ "ADC Capture Left", - /* 19 */ "ADC Capture Right", - /* 20 */ "???", - /* 21 */ "???", - /* 22 */ "???", - /* 23 */ "???", - /* 24 */ "???", - /* 25 */ "???", - /* 26 */ "???", - /* 27 */ "???", - /* 28 */ "???", - /* 29 */ "???", - /* 30 */ "???", - /* 31 */ "???", - /* 32 */ "FXBUS2_0", - /* 33 */ "FXBUS2_1", - /* 34 */ "FXBUS2_2", - /* 35 */ "FXBUS2_3", - /* 36 */ "FXBUS2_4", - /* 37 */ "FXBUS2_5", - /* 38 */ "FXBUS2_6", - /* 39 */ "FXBUS2_7", - /* 40 */ "FXBUS2_8", - /* 41 */ "FXBUS2_9", - /* 42 */ "FXBUS2_10", - /* 43 */ "FXBUS2_11", - /* 44 */ "FXBUS2_12", - /* 45 */ "FXBUS2_13", - /* 46 */ "FXBUS2_14", - /* 47 */ "FXBUS2_15", - /* 48 */ "FXBUS2_16", - /* 49 */ "FXBUS2_17", - /* 50 */ "FXBUS2_18", - /* 51 */ "FXBUS2_19", - /* 52 */ "FXBUS2_20", - /* 53 */ "FXBUS2_21", - /* 54 */ "FXBUS2_22", - /* 55 */ "FXBUS2_23", - /* 56 */ "FXBUS2_24", - /* 57 */ "FXBUS2_25", - /* 58 */ "FXBUS2_26", - /* 59 */ "FXBUS2_27", - /* 60 */ "FXBUS2_28", - /* 61 */ "FXBUS2_29", - /* 62 */ "FXBUS2_30", - /* 63 */ "FXBUS2_31" - }; - struct snd_emu10k1 *emu = entry->private_data; - unsigned int val, val1; - int nefx = emu->audigy ? 64 : 32; - const char * const *outputs = emu->audigy ? audigy_outs : creative_outs; + const char * const *inputs = emu->audigy ? + snd_emu10k1_audigy_ins : snd_emu10k1_sblive_ins; + const char * const *outputs = emu->audigy ? + snd_emu10k1_audigy_outs : snd_emu10k1_sblive_outs; + unsigned short extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask; + unsigned short extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask; + unsigned int val, val1, ptrx, psst, dsl, snda; + int nefx = emu->audigy ? 32 : 16; int idx; snd_iprintf(buffer, "EMU10K1\n\n"); snd_iprintf(buffer, "Card : %s\n", - emu->audigy ? "Audigy" : (emu->card_capabilities->ecard ? "EMU APS" : "Creative")); + emu->card_capabilities->emu_model ? "E-MU D.A.S." : + emu->card_capabilities->ecard ? "E-MU A.P.S." : + emu->audigy ? "SB Audigy" : "SB Live!"); snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); - snd_iprintf(buffer, "\n"); - snd_iprintf(buffer, "Effect Send Routing :\n"); + + snd_iprintf(buffer, "\nEffect Send Routing & Amounts:\n"); for (idx = 0; idx < NUM_G; idx++) { - val = emu->audigy ? - snd_emu10k1_ptr_read(emu, A_FXRT1, idx) : - snd_emu10k1_ptr_read(emu, FXRT, idx); - val1 = emu->audigy ? - snd_emu10k1_ptr_read(emu, A_FXRT2, idx) : - 0; + ptrx = snd_emu10k1_ptr_read(emu, PTRX, idx); + psst = snd_emu10k1_ptr_read(emu, PSST, idx); + dsl = snd_emu10k1_ptr_read(emu, DSL, idx); if (emu->audigy) { - snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i, ", + val = snd_emu10k1_ptr_read(emu, A_FXRT1, idx); + val1 = snd_emu10k1_ptr_read(emu, A_FXRT2, idx); + snda = snd_emu10k1_ptr_read(emu, A_SENDAMOUNTS, idx); + snd_iprintf(buffer, "Ch%-2i: A=%2i:%02x, B=%2i:%02x, C=%2i:%02x, D=%2i:%02x, ", idx, - val & 0x3f, - (val >> 8) & 0x3f, - (val >> 16) & 0x3f, - (val >> 24) & 0x3f); - snd_iprintf(buffer, "E=%i, F=%i, G=%i, H=%i\n", - val1 & 0x3f, - (val1 >> 8) & 0x3f, - (val1 >> 16) & 0x3f, - (val1 >> 24) & 0x3f); + val & 0x3f, REG_VAL_GET(PTRX_FXSENDAMOUNT_A, ptrx), + (val >> 8) & 0x3f, REG_VAL_GET(PTRX_FXSENDAMOUNT_B, ptrx), + (val >> 16) & 0x3f, REG_VAL_GET(PSST_FXSENDAMOUNT_C, psst), + (val >> 24) & 0x3f, REG_VAL_GET(DSL_FXSENDAMOUNT_D, dsl)); + snd_iprintf(buffer, "E=%2i:%02x, F=%2i:%02x, G=%2i:%02x, H=%2i:%02x\n", + val1 & 0x3f, (snda >> 24) & 0xff, + (val1 >> 8) & 0x3f, (snda >> 16) & 0xff, + (val1 >> 16) & 0x3f, (snda >> 8) & 0xff, + (val1 >> 24) & 0x3f, snda & 0xff); } else { - snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i\n", + val = snd_emu10k1_ptr_read(emu, FXRT, idx); + snd_iprintf(buffer, "Ch%-2i: A=%2i:%02x, B=%2i:%02x, C=%2i:%02x, D=%2i:%02x\n", idx, - (val >> 16) & 0x0f, - (val >> 20) & 0x0f, - (val >> 24) & 0x0f, - (val >> 28) & 0x0f); + (val >> 16) & 0x0f, REG_VAL_GET(PTRX_FXSENDAMOUNT_A, ptrx), + (val >> 20) & 0x0f, REG_VAL_GET(PTRX_FXSENDAMOUNT_B, ptrx), + (val >> 24) & 0x0f, REG_VAL_GET(PSST_FXSENDAMOUNT_C, psst), + (val >> 28) & 0x0f, REG_VAL_GET(DSL_FXSENDAMOUNT_D, dsl)); } } - snd_iprintf(buffer, "\nCaptured FX Outputs :\n"); - for (idx = 0; idx < nefx; idx++) { - if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) - snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); + snd_iprintf(buffer, "\nEffect Send Targets:\n"); + // Audigy actually has 64, but we don't use them all. + for (idx = 0; idx < 32; idx++) { + const char *c = snd_emu10k1_fxbus[idx]; + if (c) + snd_iprintf(buffer, " Channel %02i [%s]\n", idx, c); + } + if (!emu->card_capabilities->emu_model) { + snd_iprintf(buffer, "\nOutput Channels:\n"); + for (idx = 0; idx < 32; idx++) + if (outputs[idx] && (extout_mask & (1 << idx))) + snd_iprintf(buffer, " Channel %02i [%s]\n", idx, outputs[idx]); + snd_iprintf(buffer, "\nInput Channels:\n"); + for (idx = 0; idx < 16; idx++) + if (inputs[idx] && (extin_mask & (1 << idx))) + snd_iprintf(buffer, " Channel %02i [%s]\n", idx, inputs[idx]); + snd_iprintf(buffer, "\nMultichannel Capture Sources:\n"); + for (idx = 0; idx < nefx; idx++) + if (emu->efx_voices_mask[0] & (1 << idx)) + snd_iprintf(buffer, " Channel %02i [Output: %s]\n", + idx, outputs[idx] ? outputs[idx] : "???"); + if (emu->audigy) { + for (idx = 0; idx < 32; idx++) + if (emu->efx_voices_mask[1] & (1 << idx)) + snd_iprintf(buffer, " Channel %02i [Input: %s]\n", + idx + 32, inputs[idx] ? inputs[idx] : "???"); + } else { + for (idx = 0; idx < 16; idx++) { + if (emu->efx_voices_mask[0] & ((1 << 16) << idx)) { + if (emu->card_capabilities->sblive51) { + s8 c = snd_emu10k1_sblive51_fxbus2_map[idx]; + if (c == -1) + snd_iprintf(buffer, " Channel %02i [Output: %s]\n", + idx + 16, outputs[idx + 16]); + else + snd_iprintf(buffer, " Channel %02i [Input: %s]\n", + idx + 16, inputs[c]); + } else { + snd_iprintf(buffer, " Channel %02i [Input: %s]\n", + idx + 16, inputs[idx] ? inputs[idx] : "???"); + } + } + } + } } - snd_iprintf(buffer, "\nAll FX Outputs :\n"); - for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) - snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); } static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, @@ -226,27 +163,40 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry, struct snd_emu10k1 *emu = entry->private_data; u32 value; u32 value2; - 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"); - } - snd_emu1010_fpga_read(emu, 0x20, &value); - if ((value & 0x4) == 0) { - snd_emu1010_fpga_read(emu, 0x28, &value); - snd_emu1010_fpga_read(emu, 0x29, &value2); - rate = 0x1770000 / (((value << 5) | value2)+1); - snd_iprintf(buffer, "SPDIF Locked : %d\n", rate); - } else { - snd_iprintf(buffer, "SPDIF Unlocked\n"); + // This represents the S/PDIF lock status on 0404b, which is + // kinda weird and unhelpful, because monitoring it via IRQ is + // impractical (one gets an IRQ flood as long as it is desynced). + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &value); + snd_iprintf(buffer, "Lock status 1: %#x\n", value & 0x10); + + // Bit 0x1 in LO being 0 is supposedly for ADAT lock. + // The registers are always all zero on 0404b. + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_LO, &value); + snd_emu1010_fpga_read(emu, EMU_HANA_LOCK_STS_HI, &value2); + snd_iprintf(buffer, "Lock status 2: %#x %#x\n", value, value2); + + snd_iprintf(buffer, "S/PDIF rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_SPDIF_IN)); + if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) { + snd_iprintf(buffer, "ADAT rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_HANA_ADAT_IN)); + snd_iprintf(buffer, "Dock rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_2ND_HANA)); } + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU0404 || + emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) + snd_iprintf(buffer, "BNC rate: %dHz\n", + snd_emu1010_get_raw_rate(emu, EMU_HANA_WCLOCK_SYNC_BNC)); + + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value); + if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) + snd_iprintf(buffer, "\nS/PDIF input invalid\n"); + else + snd_iprintf(buffer, "\nS/PDIF mode: %s%s\n", + value & EMU_HANA_SPDIF_MODE_RX_PRO ? "professional" : "consumer", + value & EMU_HANA_SPDIF_MODE_RX_NOCOPY ? ", no copy" : ""); } else { snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF In", CDCS, CDSRCS); snd_emu10k1_proc_spdif_status(emu, buffer, "Optical or Coax S/PDIF In", GPSCS, GPSRCS); @@ -273,37 +223,148 @@ static void snd_emu10k1_proc_rates_read(struct snd_info_entry *entry, } } -static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry, +struct emu10k1_reg_entry { + unsigned short base, size; + const char *name; +}; + +static const struct emu10k1_reg_entry sblive_reg_entries[] = { + { 0, 0x10, "FXBUS" }, + { 0x10, 0x10, "EXTIN" }, + { 0x20, 0x10, "EXTOUT" }, + { 0x30, 0x10, "FXBUS2" }, + { 0x40, 0x20, NULL }, // Constants + { 0x100, 0x100, "GPR" }, + { 0x200, 0x80, "ITRAM_DATA" }, + { 0x280, 0x20, "ETRAM_DATA" }, + { 0x300, 0x80, "ITRAM_ADDR" }, + { 0x380, 0x20, "ETRAM_ADDR" }, + { 0x400, 0, NULL } +}; + +static const struct emu10k1_reg_entry audigy_reg_entries[] = { + { 0, 0x40, "FXBUS" }, + { 0x40, 0x10, "EXTIN" }, + { 0x50, 0x10, "P16VIN" }, + { 0x60, 0x20, "EXTOUT" }, + { 0x80, 0x20, "FXBUS2" }, + { 0xa0, 0x10, "EMU32OUTH" }, + { 0xb0, 0x10, "EMU32OUTL" }, + { 0xc0, 0x20, NULL }, // Constants + // This can't be quite right - overlap. + //{ 0x100, 0xc0, "ITRAM_CTL" }, + //{ 0x1c0, 0x40, "ETRAM_CTL" }, + { 0x160, 0x20, "A3_EMU32IN" }, + { 0x1e0, 0x20, "A3_EMU32OUT" }, + { 0x200, 0xc0, "ITRAM_DATA" }, + { 0x2c0, 0x40, "ETRAM_DATA" }, + { 0x300, 0xc0, "ITRAM_ADDR" }, + { 0x3c0, 0x40, "ETRAM_ADDR" }, + { 0x400, 0x200, "GPR" }, + { 0x600, 0, NULL } +}; + +static const char * const emu10k1_const_entries[] = { + "C_00000000", + "C_00000001", + "C_00000002", + "C_00000003", + "C_00000004", + "C_00000008", + "C_00000010", + "C_00000020", + "C_00000100", + "C_00010000", + "C_00000800", + "C_10000000", + "C_20000000", + "C_40000000", + "C_80000000", + "C_7fffffff", + "C_ffffffff", + "C_fffffffe", + "C_c0000000", + "C_4f1bbcdc", + "C_5a7ef9db", + "C_00100000", + "GPR_ACCU", + "GPR_COND", + "GPR_NOISE0", + "GPR_NOISE1", + "GPR_IRQ", + "GPR_DBAC", + "GPR_DBACE", + "???", +}; + +static int disasm_emu10k1_reg(char *buffer, + const struct emu10k1_reg_entry *entries, + unsigned reg, const char *pfx) +{ + for (int i = 0; ; i++) { + unsigned base = entries[i].base; + unsigned size = entries[i].size; + if (!size) + return sprintf(buffer, "%s0x%03x", pfx, reg); + if (reg >= base && reg < base + size) { + const char *name = entries[i].name; + reg -= base; + if (name) + return sprintf(buffer, "%s%s(%u)", pfx, name, reg); + return sprintf(buffer, "%s%s", pfx, emu10k1_const_entries[reg]); + } + } +} + +static int disasm_sblive_reg(char *buffer, unsigned reg, const char *pfx) +{ + return disasm_emu10k1_reg(buffer, sblive_reg_entries, reg, pfx); +} + +static int disasm_audigy_reg(char *buffer, unsigned reg, const char *pfx) +{ + return disasm_emu10k1_reg(buffer, audigy_reg_entries, reg, pfx); +} + +static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { u32 pc; struct snd_emu10k1 *emu = entry->private_data; + static const char * const insns[16] = { + "MAC0", "MAC1", "MAC2", "MAC3", "MACINT0", "MACINT1", "ACC3", "MACMV", + "ANDXOR", "TSTNEG", "LIMITGE", "LIMITLT", "LOG", "EXP", "INTERP", "SKIP", + }; + static const char spaces[] = " "; + const int nspaces = sizeof(spaces) - 1; snd_iprintf(buffer, "FX8010 Instruction List '%s'\n", emu->fx8010.name); snd_iprintf(buffer, " Code dump :\n"); for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) { u32 low, high; + int len; + char buf[100]; + char *bufp = buf; low = snd_emu10k1_efx_read(emu, pc * 2); high = snd_emu10k1_efx_read(emu, pc * 2 + 1); - if (emu->audigy) - snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n", - (high >> 24) & 0x0f, - (high >> 12) & 0x7ff, - (high >> 0) & 0x7ff, - (low >> 12) & 0x7ff, - (low >> 0) & 0x7ff, - pc, - high, low); - else - snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n", - (high >> 20) & 0x0f, - (high >> 10) & 0x3ff, - (high >> 0) & 0x3ff, - (low >> 10) & 0x3ff, - (low >> 0) & 0x3ff, - pc, - high, low); + if (emu->audigy) { + bufp += sprintf(bufp, " %-7s ", insns[(high >> 24) & 0x0f]); + bufp += disasm_audigy_reg(bufp, (high >> 12) & 0x7ff, ""); + bufp += disasm_audigy_reg(bufp, (high >> 0) & 0x7ff, ", "); + bufp += disasm_audigy_reg(bufp, (low >> 12) & 0x7ff, ", "); + bufp += disasm_audigy_reg(bufp, (low >> 0) & 0x7ff, ", "); + } else { + bufp += sprintf(bufp, " %-7s ", insns[(high >> 20) & 0x0f]); + bufp += disasm_sblive_reg(bufp, (high >> 10) & 0x3ff, ""); + bufp += disasm_sblive_reg(bufp, (high >> 0) & 0x3ff, ", "); + bufp += disasm_sblive_reg(bufp, (low >> 10) & 0x3ff, ", "); + bufp += disasm_sblive_reg(bufp, (low >> 0) & 0x3ff, ", "); + } + len = (int)(ptrdiff_t)(bufp - buf); + snd_iprintf(buffer, "%s %s /* 0x%04x: 0x%08x%08x */\n", + buf, &spaces[nspaces - clamp(65 - len, 0, nspaces)], + pc, high, low); } } @@ -365,21 +426,32 @@ 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]); } } #ifdef CONFIG_SND_DEBUG + +static void snd_emu_proc_emu1010_link_read(struct snd_emu10k1 *emu, + struct snd_info_buffer *buffer, + u32 dst) +{ + u32 src = snd_emu1010_fpga_link_dst_src_read(emu, dst); + snd_iprintf(buffer, "%04x: %04x\n", dst, src); +} + static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -390,7 +462,39 @@ static void snd_emu_proc_emu1010_reg_read(struct snd_info_entry *entry, for(i = 0; i < 0x40; i+=1) { snd_emu1010_fpga_read(emu, i, &value); - snd_iprintf(buffer, "%02X: %08X, %02X\n", i, value, (value >> 8) & 0x7f); + snd_iprintf(buffer, "%02x: %02x\n", i, value); + } + + snd_iprintf(buffer, "\nEMU1010 Routes:\n\n"); + + for (i = 0; i < 16; i++) // To Alice2/Tina[2] via EMU32 + snd_emu_proc_emu1010_link_read(emu, buffer, i); + if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) + for (i = 0; i < 32; i++) // To Dock via EDI + snd_emu_proc_emu1010_link_read(emu, buffer, 0x100 + i); + if (emu->card_capabilities->emu_model != EMU_MODEL_EMU1616) + for (i = 0; i < 8; i++) // To Hamoa/local + snd_emu_proc_emu1010_link_read(emu, buffer, 0x200 + i); + for (i = 0; i < 8; i++) // To Hamoa/Mana/local + snd_emu_proc_emu1010_link_read(emu, buffer, 0x300 + i); + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { + for (i = 0; i < 16; i++) // To Tina2 via EMU32 + snd_emu_proc_emu1010_link_read(emu, buffer, 0x400 + i); + } else if (emu->card_capabilities->emu_model != EMU_MODEL_EMU0404) { + for (i = 0; i < 8; i++) // To Hana ADAT + snd_emu_proc_emu1010_link_read(emu, buffer, 0x400 + i); + if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010B) { + for (i = 0; i < 16; i++) // To Tina via EMU32 + snd_emu_proc_emu1010_link_read(emu, buffer, 0x500 + i); + } else { + // To Alice2 via I2S + snd_emu_proc_emu1010_link_read(emu, buffer, 0x500); + snd_emu_proc_emu1010_link_read(emu, buffer, 0x501); + snd_emu_proc_emu1010_link_read(emu, buffer, 0x600); + snd_emu_proc_emu1010_link_read(emu, buffer, 0x601); + snd_emu_proc_emu1010_link_read(emu, buffer, 0x700); + snd_emu_proc_emu1010_link_read(emu, buffer, 0x701); + } } } @@ -399,13 +503,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 +515,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); } } } @@ -433,15 +531,14 @@ static unsigned int snd_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) { - unsigned long flags; unsigned int regptr, val; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); val = inl(emu->port + iobase + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); return val; } @@ -452,14 +549,13 @@ static void snd_ptr_write(struct snd_emu10k1 *emu, unsigned int data) { unsigned int regptr; - unsigned long flags; regptr = (reg << 16) | chn; - spin_lock_irqsave(&emu->emu_lock, flags); + spin_lock_irq(&emu->emu_lock); outl(regptr, emu->port + iobase + PTR); outl(data, emu->port + iobase + DATA); - spin_unlock_irqrestore(&emu->emu_lock, flags); + spin_unlock_irq(&emu->emu_lock); } @@ -477,10 +573,7 @@ static void snd_emu_proc_ptr_reg_read(struct snd_info_entry *entry, for(i = offset; i < offset+length; i++) { snd_iprintf(buffer, "%02X: ",i); for (j = 0; j < voices; j++) { - if(iobase == 0) - value = snd_ptr_read(emu, 0, i, j); - else - value = snd_ptr_read(emu, 0x20, i, j); + value = snd_ptr_read(emu, iobase, i, j); snd_iprintf(buffer, "%08lX ", value); } snd_iprintf(buffer, "\n"); @@ -488,7 +581,8 @@ static void snd_emu_proc_ptr_reg_read(struct snd_info_entry *entry, } static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, - struct snd_info_buffer *buffer, int iobase) + struct snd_info_buffer *buffer, + int iobase, int length, int voices) { struct snd_emu10k1 *emu = entry->private_data; char line[64]; @@ -496,7 +590,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3) + if (reg < length && channel_id < voices) snd_ptr_write(emu, iobase, reg, channel_id, val); } } @@ -504,13 +598,15 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, static void snd_emu_proc_ptr_reg_write00(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_emu_proc_ptr_reg_write(entry, buffer, 0); + snd_emu_proc_ptr_reg_write(entry, buffer, 0, 0x80, 64); } static void snd_emu_proc_ptr_reg_write20(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_emu_proc_ptr_reg_write(entry, buffer, 0x20); + struct snd_emu10k1 *emu = entry->private_data; + snd_emu_proc_ptr_reg_write(entry, buffer, 0x20, + emu->card_capabilities->ca0108_chip ? 0xa0 : 0x80, 4); } @@ -566,15 +662,19 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) snd_card_rw_proc_new(emu->card, "ptr_regs00b", emu, snd_emu_proc_ptr_reg_read00b, snd_emu_proc_ptr_reg_write00); - snd_card_rw_proc_new(emu->card, "ptr_regs20a", emu, - snd_emu_proc_ptr_reg_read20a, - snd_emu_proc_ptr_reg_write20); - snd_card_rw_proc_new(emu->card, "ptr_regs20b", emu, - snd_emu_proc_ptr_reg_read20b, - snd_emu_proc_ptr_reg_write20); - snd_card_rw_proc_new(emu->card, "ptr_regs20c", emu, - snd_emu_proc_ptr_reg_read20c, - snd_emu_proc_ptr_reg_write20); + if (!emu->card_capabilities->emu_model && + (emu->card_capabilities->ca0151_chip || emu->card_capabilities->ca0108_chip)) { + snd_card_rw_proc_new(emu->card, "ptr_regs20a", emu, + snd_emu_proc_ptr_reg_read20a, + snd_emu_proc_ptr_reg_write20); + snd_card_rw_proc_new(emu->card, "ptr_regs20b", emu, + snd_emu_proc_ptr_reg_read20b, + snd_emu_proc_ptr_reg_write20); + if (emu->card_capabilities->ca0108_chip) + snd_card_rw_proc_new(emu->card, "ptr_regs20c", emu, + snd_emu_proc_ptr_reg_read20c, + snd_emu_proc_ptr_reg_write20); + } #endif snd_card_ro_proc_new(emu->card, "emu10k1", emu, snd_emu10k1_proc_read); diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index e15092ce9848..74df2330015f 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -1,14 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> + * Lee Revell <rlrevell@joe-job.com> + * James Courtier-Dutton <James@superbug.co.uk> + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * Creative Labs, Inc. - * Routines for control of EMU10K1 chips - * - * BUGS: - * -- * - * TODO: - * -- + * Routines for control of EMU10K1 chips */ #include <linux/time.h> @@ -18,33 +16,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 +64,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) @@ -95,8 +133,8 @@ unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, regptr = (reg << 16) | chn; spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + 0x20 + PTR); - val = inl(emu->port + 0x20 + DATA); + outl(regptr, emu->port + PTR2); + val = inl(emu->port + DATA2); spin_unlock_irqrestore(&emu->emu_lock, flags); return val; } @@ -112,8 +150,8 @@ void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, regptr = (reg << 16) | chn; spin_lock_irqsave(&emu->emu_lock, flags); - outl(regptr, emu->port + 0x20 + PTR); - outl(data, emu->port + 0x20 + DATA); + outl(regptr, emu->port + PTR2); + outl(data, emu->port + DATA2); spin_unlock_irqrestore(&emu->emu_lock, flags); } @@ -128,7 +166,7 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, /* This function is not re-entrant, so protect against it. */ spin_lock(&emu->spi_lock); if (emu->card_capabilities->ca0108_chip) - reg = 0x3c; /* PTR20, reg 0x3c */ + reg = P17V_SPI; else { /* For other chip types the SPI register * is currently unknown. */ @@ -233,56 +271,162 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, return err; } -int 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 (reg > 0x3f) - return 1; + if (snd_BUG_ON(reg > 0x3f)) + return; reg += 0x40; /* 0x40 upwards are registers. */ - if (value > 0x3f) /* 0 to 0x3f are values */ - return 1; - spin_lock_irqsave(&emu->emu_lock, flags); - outl(reg, emu->port + A_IOCFG); + if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */ + return; + outw(reg, emu->port + A_GPIO); udelay(10); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ udelay(10); - outl(value, emu->port + A_IOCFG); + outw(value, emu->port + A_GPIO); udelay(10); - outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ - spin_unlock_irqrestore(&emu->emu_lock, flags); - - return 0; + outw(value | 0x80 , emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ } -int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) +void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value) { unsigned long flags; - if (reg > 0x3f) - return 1; - reg += 0x40; /* 0x40 upwards are registers. */ + spin_lock_irqsave(&emu->emu_lock, flags); - outl(reg, emu->port + A_IOCFG); + snd_emu1010_fpga_write_locked(emu, reg, value); + spin_unlock_irqrestore(&emu->emu_lock, flags); +} + +static void snd_emu1010_fpga_read_locked(struct snd_emu10k1 *emu, u32 reg, u32 *value) +{ + // The higest input pin is used as the designated interrupt trigger, + // so it needs to be masked out. + // But note that any other input pin change will also cause an IRQ, + // so using this function often causes an IRQ as a side effect. + u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f; + if (snd_BUG_ON(reg > 0x3f)) + return; + reg += 0x40; /* 0x40 upwards are registers. */ + outw(reg, emu->port + A_GPIO); udelay(10); - outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + outw(reg | 0x80, emu->port + A_GPIO); /* High bit clocks the value into the fpga. */ udelay(10); - *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); - spin_unlock_irqrestore(&emu->emu_lock, flags); + *value = ((inw(emu->port + A_GPIO) >> 8) & mask); +} - return 0; +void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value) +{ + unsigned long flags; + + spin_lock_irqsave(&emu->emu_lock, flags); + snd_emu1010_fpga_read_locked(emu, reg, value); + spin_unlock_irqrestore(&emu->emu_lock, flags); } /* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */ -int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src) +void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src) { - snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) ); - snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) ); - snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) ); - snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) ); + unsigned long flags; + + if (snd_BUG_ON(dst & ~0x71f)) + return; + if (snd_BUG_ON(src & ~0x71f)) + return; + 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); +} + +u32 snd_emu1010_fpga_link_dst_src_read(struct snd_emu10k1 *emu, u32 dst) +{ + unsigned long flags; + u32 hi, lo; + + if (snd_BUG_ON(dst & ~0x71f)) + return 0; + 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_read_locked(emu, EMU_HANA_SRCHI, &hi); + snd_emu1010_fpga_read_locked(emu, EMU_HANA_SRCLO, &lo); + spin_unlock_irqrestore(&emu->emu_lock, flags); + return (hi << 8) | lo; +} + +int snd_emu1010_get_raw_rate(struct snd_emu10k1 *emu, u8 src) +{ + u32 reg_lo, reg_hi, value, value2; + + switch (src) { + case EMU_HANA_WCLOCK_HANA_SPDIF_IN: + snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &value); + if (value & EMU_HANA_SPDIF_MODE_RX_INVALID) + return 0; + reg_lo = EMU_HANA_WC_SPDIF_LO; + reg_hi = EMU_HANA_WC_SPDIF_HI; + break; + case EMU_HANA_WCLOCK_HANA_ADAT_IN: + reg_lo = EMU_HANA_WC_ADAT_LO; + reg_hi = EMU_HANA_WC_ADAT_HI; + break; + case EMU_HANA_WCLOCK_SYNC_BNC: + reg_lo = EMU_HANA_WC_BNC_LO; + reg_hi = EMU_HANA_WC_BNC_HI; + break; + case EMU_HANA_WCLOCK_2ND_HANA: + reg_lo = EMU_HANA2_WC_SPDIF_LO; + reg_hi = EMU_HANA2_WC_SPDIF_HI; + break; + default: + return 0; + } + snd_emu1010_fpga_read(emu, reg_hi, &value); + snd_emu1010_fpga_read(emu, reg_lo, &value2); + // FIXME: The /4 is valid for 0404b, but contradicts all other info. + return 0x1770000 / 4 / (((value << 5) | value2) + 1); +} + +void snd_emu1010_update_clock(struct snd_emu10k1 *emu) +{ + int clock; + u32 leds; + + switch (emu->emu1010.wclock) { + case EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X: + clock = 44100; + leds = EMU_HANA_DOCK_LEDS_2_44K; + break; + case EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X: + clock = 48000; + leds = EMU_HANA_DOCK_LEDS_2_48K; + break; + default: + clock = snd_emu1010_get_raw_rate( + emu, emu->emu1010.wclock & EMU_HANA_WCLOCK_SRC_MASK); + // The raw rate reading is rather coarse (it cannot accurately + // represent 44.1 kHz) and fluctuates slightly. Luckily, the + // clock comes from digital inputs, which use standardized rates. + // So we round to the closest standard rate and ignore discrepancies. + if (clock < 46000) { + clock = 44100; + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_44K; + } else { + clock = 48000; + leds = EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_48K; + } + break; + } + emu->emu1010.word_clock = clock; - return 0; + // FIXME: this should probably represent the AND of all currently + // used sources' lock status. But we don't know how to get that ... + leds |= EMU_HANA_DOCK_LEDS_2_LOCK; + + snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, leds); } void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) @@ -313,7 +457,6 @@ void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenu unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -333,7 +476,6 @@ void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicen unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -352,7 +494,6 @@ void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum) unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(CLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -370,7 +511,6 @@ void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned i unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -390,7 +530,6 @@ void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned unsigned int val; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIEH << 16, emu->port + PTR); val = inl(emu->port + DATA); @@ -409,7 +548,6 @@ void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(HLIPH << 16, emu->port + PTR); voicenum = 1 << (voicenum - 32); @@ -421,13 +559,13 @@ 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; unsigned int sol; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); @@ -447,7 +585,6 @@ void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voi unsigned int sol; spin_lock_irqsave(&emu->emu_lock, flags); - /* voice interrupt */ if (voicenum >= 32) { outl(SOLEH << 16, emu->port + PTR); sol = inl(emu->port + DATA); @@ -460,6 +597,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) { @@ -503,64 +723,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 ebb2275efb6c..71aa90b9cc88 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -3,12 +3,6 @@ * Copyright (c) by Jaroslav Kysela <perex@perex.cz> * Creative Labs, Inc. * Routines for IRQ control of EMU10K1 chips - * - * BUGS: - * -- - * - * TODO: - * -- */ #include <linux/time.h> @@ -18,19 +12,22 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) { struct snd_emu10k1 *emu = dev_id; - unsigned int status, status2, orig_status, orig_status2; + unsigned int status, orig_status; 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 +41,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 +63,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 +78,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); @@ -139,61 +137,26 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) status &= ~IPR_FXDSP; } if (status & IPR_P16V) { - while ((status2 = inl(emu->port + IPR2)) != 0) { - u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ - struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]); - struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice); - - /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */ - orig_status2 = status2; - if(status2 & mask) { - if(pvoice->use) { - snd_pcm_period_elapsed(pvoice->epcm->substream); - } else { - dev_err(emu->card->dev, - "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", - status2, mask, pvoice, - pvoice->use); - } - } - if(status2 & 0x110000) { - /* dev_info(emu->card->dev, "capture int found\n"); */ - if(cvoice->use) { - /* dev_info(emu->card->dev, "capture period_elapsed\n"); */ - snd_pcm_period_elapsed(cvoice->epcm->substream); - } - } - outl(orig_status2, emu->port + IPR2); /* ack all */ - } + if (emu->p16v_interrupt) + emu->p16v_interrupt(emu); + else + outl(0, emu->port + INTE2); status &= ~IPR_P16V; } + if (status & IPR_A_GPIO) { + if (emu->gpio_interrupt) + emu->gpio_interrupt(emu); + else + snd_emu10k1_intr_disable(emu, INTE_A_GPIOENABLE); + status &= ~IPR_A_GPIO; + } 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 94b8d5b08225..20b07117574b 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -169,16 +169,20 @@ static int unmap_memblk(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk) struct snd_emu10k1_memblk *q; /* calculate the expected size of empty region */ - if ((p = blk->mapped_link.prev) != &emu->mapped_link_head) { + p = blk->mapped_link.prev; + if (p != &emu->mapped_link_head) { q = get_emu10k1_memblk(p, mapped_link); start_page = q->mapped_page + q->pages; - } else + } else { start_page = 1; - if ((p = blk->mapped_link.next) != &emu->mapped_link_head) { + } + p = blk->mapped_link.next; + if (p != &emu->mapped_link_head) { q = get_emu10k1_memblk(p, mapped_link); end_page = q->mapped_page; - } else + } else { end_page = (emu->address_mode ? MAX_ALIGN_PAGES1 : MAX_ALIGN_PAGES0); + } /* remove links */ list_del(&blk->mapped_link); @@ -267,7 +271,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b spin_unlock_irqrestore(&emu->memblk_lock, flags); return 0; } - if ((err = map_memblk(emu, blk)) < 0) { + err = map_memblk(emu, blk); + if (err < 0) { /* no enough page - try to unmap some blocks */ /* starting from the oldest block */ p = emu->mapped_order_link_head.next; @@ -310,16 +315,14 @@ 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; } /* fill buffer addresses but pointers are not stored so that - * snd_free_pci_page() is not called in in synth_free() + * snd_free_pci_page() is not called in synth_free() */ idx = 0; for (page = blk->first_page; page <= blk->last_page; page++, idx++) { @@ -375,7 +378,7 @@ int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size, struct snd_dma_buffer *dmab) { if (emu->iommu_workaround) { - size_t npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + size_t npages = DIV_ROUND_UP(size, PAGE_SIZE); size_t size_real = npages * PAGE_SIZE; /* @@ -454,13 +457,15 @@ static void get_single_page_range(struct snd_util_memhdr *hdr, struct snd_emu10k1_memblk *q; int first_page, last_page; first_page = blk->first_page; - if ((p = blk->mem.list.prev) != &hdr->block) { + p = blk->mem.list.prev; + if (p != &hdr->block) { q = get_emu10k1_memblk(p, mem.list); if (q->last_page == first_page) first_page++; /* first page was already allocated */ } last_page = blk->last_page; - if ((p = blk->mem.list.next) != &hdr->block) { + p = blk->mem.list.next; + if (p != &hdr->block) { q = get_emu10k1_memblk(p, mem.list); if (q->first_page == last_page) last_page--; /* last page was already allocated */ diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 1099f102b365..e7f097cae574 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -149,42 +149,19 @@ static const struct snd_pcm_hardware snd_p16v_capture_hw = { .fifo_size = 0, }; -static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime) -{ - struct snd_emu10k1_pcm *epcm = runtime->private_data; - - kfree(epcm); -} - /* open_playback callback */ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - struct snd_emu10k1_voice *channel = &(emu->p16v_voices[channel_id]); - struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int err; - epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ - - if (epcm == NULL) - return -ENOMEM; - epcm->emu = emu; - epcm->substream = substream; /* dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ - runtime->private_data = epcm; - runtime->private_free = snd_p16v_pcm_free_substream; runtime->hw = snd_p16v_playback_hw; - channel->emu = emu; - channel->number = channel_id; - - channel->use=1; #if 0 /* debug */ dev_dbg(emu->card->dev, "p16v: open channel_id=%d, channel=%p, use=0x%x\n", @@ -193,8 +170,8 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea channel_id, chip, channel); #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ - channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; runtime->sync.id32[0] = substream->pcm->card->number; @@ -204,45 +181,22 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea return 0; } + /* open_capture callback */ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream, int channel_id) { - struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); - struct snd_emu10k1_voice *channel = &(emu->p16v_capture_voice); - struct snd_emu10k1_pcm *epcm; struct snd_pcm_runtime *runtime = substream->runtime; int err; - epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ - - if (epcm == NULL) - return -ENOMEM; - epcm->emu = emu; - epcm->substream = substream; /* dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ - runtime->private_data = epcm; - runtime->private_free = snd_p16v_pcm_free_substream; runtime->hw = snd_p16v_capture_hw; - channel->emu = emu; - channel->number = channel_id; - - channel->use=1; -#if 0 /* debug */ - dev_dbg(emu->card->dev, - "p16v: open channel_id=%d, channel=%p, use=0x%x\n", - channel_id, channel, channel->use); - dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", - channel_id, chip, channel); -#endif /* debug */ - /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ - channel->epcm = epcm; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (err < 0) return err; return 0; @@ -252,22 +206,12 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream /* close callback */ static int snd_p16v_pcm_close_playback(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; - emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use = 0; - /* FIXME: maybe zero others */ return 0; } /* close callback */ static int snd_p16v_pcm_close_capture(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; - emu->p16v_capture_voice.use = 0; - /* FIXME: maybe zero others */ return 0; } @@ -288,7 +232,7 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); + u32 *table_base = (u32 *)(emu->p16v_buffer->area+(8*16*channel)); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; u32 tmp; @@ -306,23 +250,28 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) runtime->dma_addr, runtime->dma_area, table_base); dev_dbg(emu->card->dev, "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", - emu->p16v_buffer.addr, emu->p16v_buffer.area, - emu->p16v_buffer.bytes); + emu->p16v_buffer->addr, emu->p16v_buffer->area, + emu->p16v_buffer->bytes); #endif /* debug */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); + tmp &= ~(A_SPDIF_RATE_MASK | A_EHC_SRC48_MASK); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_44100 | A_EHC_SRC48_44); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_96000 | A_EHC_SRC48_96); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_192000 | A_EHC_SRC48_192); break; case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000); + snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, + tmp | A_SPDIF_48000 | A_EHC_SRC48_BYPASS); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ @@ -331,15 +280,15 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) table_base[(i*2)+1]=period_size_bytes<<16; } - snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel)); + snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer->addr+(8*16*channel)); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); - snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); - snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); + snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_END_ADDRESS, channel, 0); + snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_POINTER, channel, 0); return 0; } @@ -350,7 +299,6 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int channel = substream->pcm->device - emu->p16v_device_offset; - u32 tmp; /* dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, " @@ -360,24 +308,23 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); */ - tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); switch (runtime->rate) { case 44100: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_44100); break; case 96000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_96000); break; case 192000: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_192000); break; case 48000: default: - snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000); + snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_48000); break; } /* FIXME: Check emu->buffer.size before actually writing to it. */ - snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); + snd_emu10k1_ptr20_write(emu, CAPTURE_FIFO_POINTER, channel, 0); snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); @@ -409,13 +356,48 @@ static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) spin_unlock_irqrestore(&emu->emu_lock, flags); } +static void snd_p16v_interrupt(struct snd_emu10k1 *emu) +{ + unsigned int status; + + while ((status = inl(emu->port + IPR2)) != 0) { + u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ + + /* dev_dbg(emu->card->dev, "p16v status=0x%x\n", status); */ + if (status & mask) { + struct snd_pcm_substream *substream = + emu->pcm_p16v->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (runtime && runtime->private_data) { + snd_pcm_period_elapsed(substream); + } else { + dev_err(emu->card->dev, + "p16v: status: 0x%08x, mask=0x%08x\n", + status, mask); + } + } + if (status & 0x110000) { + struct snd_pcm_substream *substream = + emu->pcm_p16v->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + struct snd_pcm_runtime *runtime = substream->runtime; + + /* dev_info(emu->card->dev, "capture int found\n"); */ + if (runtime && runtime->private_data) { + /* dev_info(emu->card->dev, "capture period_elapsed\n"); */ + snd_pcm_period_elapsed(substream); + } + } + outl(status, emu->port + IPR2); /* ack all */ + } +} + /* trigger_playback callback */ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, int cmd) { struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime; - struct snd_emu10k1_pcm *epcm; int channel; int result = 0; struct snd_pcm_substream *s; @@ -437,10 +419,9 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, s->stream != SNDRV_PCM_STREAM_PLAYBACK) continue; runtime = s->runtime; - epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */ - epcm->running = running; + runtime->private_data = (void *)(ptrdiff_t)running; basic |= (0x1<<channel); inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); snd_pcm_trigger_done(s, substream); @@ -469,7 +450,6 @@ static int snd_p16v_pcm_trigger_capture(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 channel = 0; int result = 0; u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; @@ -478,13 +458,13 @@ static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: snd_p16v_intr_enable(emu, inte); snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); - epcm->running = 1; + runtime->private_data = (void *)1; break; case SNDRV_PCM_TRIGGER_STOP: snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); snd_p16v_intr_disable(emu, inte); //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); - epcm->running = 0; + runtime->private_data = NULL; break; default: result = -EINVAL; @@ -499,10 +479,10 @@ snd_p16v_pcm_pointer_playback(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; snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; int channel = substream->pcm->device - emu->p16v_device_offset; - if (!epcm->running) + + if (!runtime->private_data) return 0; ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); @@ -524,11 +504,10 @@ snd_p16v_pcm_pointer_capture(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; snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; int channel = 0; - if (!epcm->running) + if (!runtime->private_data) return 0; ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); @@ -565,20 +544,6 @@ static const struct snd_pcm_ops snd_p16v_capture_ops = { .pointer = snd_p16v_pcm_pointer_capture, }; - -int snd_p16v_free(struct snd_emu10k1 *chip) -{ - // release the data - if (chip->p16v_buffer.area) { - snd_dma_free_pages(&chip->p16v_buffer); - /* - dev_dbg(chip->card->dev, "period lables free: %p\n", - &chip->p16v_buffer); - */ - } - return 0; -} - int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) { struct snd_pcm *pcm; @@ -589,7 +554,8 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; - if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) + err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm); + if (err < 0) return err; pcm->private_data = emu; @@ -602,6 +568,7 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "p16v"); emu->pcm_p16v = pcm; + emu->p16v_interrupt = snd_p16v_interrupt; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; @@ -808,8 +775,8 @@ int snd_p16v_mixer(struct snd_emu10k1 *emu) struct snd_card *card = emu->card; for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) { - if ((err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], - emu))) < 0) + err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], emu)); + if (err < 0) return err; } return 0; diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h index 3cdafa311617..95ab8071751b 100644 --- a/sound/pci/emu10k1/p16v.h +++ b/sound/pci/emu10k1/p16v.h @@ -2,69 +2,13 @@ /* * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> * Driver p16v chips - * Version: 0.21 - * - * FEATURES currently supported: - * Output fixed at S32_LE, 2 channel to hw:0,0 - * Rates: 44.1, 48, 96, 192. - * - * Changelog: - * 0.8 - * Use separate card based buffer for periods table. - * 0.9 - * Use 2 channel output streams instead of 8 channel. - * (8 channel output streams might be good for ASIO type output) - * Corrected speaker output, so Front -> Front etc. - * 0.10 - * Fixed missed interrupts. - * 0.11 - * Add Sound card model number and names. - * Add Analog volume controls. - * 0.12 - * Corrected playback interrupts. Now interrupt per period, instead of half period. - * 0.13 - * Use single trigger for multichannel. - * 0.14 - * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. - * 0.15 - * Force buffer_size / period_size == INTEGER. - * 0.16 - * Update p16v.c to work with changed alsa api. - * 0.17 - * Update p16v.c to work with changed alsa api. Removed boot_devs. - * 0.18 - * Merging with snd-emu10k1 driver. - * 0.19 - * One stereo channel at 24bit now works. - * 0.20 - * Added better register defines. - * 0.21 - * Split from p16v.c - * - * BUGS: - * Some stability problems when unloading the snd-p16v kernel module. - * -- - * - * TODO: - * SPDIF out. - * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. - * Currently capture fixed at 48000Hz. - * - * -- - * GENERAL INFO: - * Model: SB0240 - * P16V Chip: CA0151-DBS - * Audigy 2 Chip: CA0102-IAT - * AC97 Codec: STAC 9721 - * ADC: Philips 1361T (Stereo 24bit) - * DAC: CS4382-K (8-channel, 24bit, 192Khz) * * This code was initially based on code from ALSA's emu10k1x.c which is: * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> */ /********************************************************************************************************/ -/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ +/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ /********************************************************************************************************/ /* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE. diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 3a6568346fad..ee4f4ab4b79c 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h @@ -2,12 +2,11 @@ /* * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> * Driver p17v chips - * Version: 0.01 */ /******************************************************************************/ -/* Audigy2Value Tina (P17V) pointer-offset register set, - * accessed through the PTR20 and DATA24 registers */ +/* Audigy2Value Tina (P17V) pointer-offset register set, */ +/* accessed through the PTR2 and DATA2 registers */ /******************************************************************************/ /* 00 - 07: Not used */ diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index c2803000aace..bb2478319361 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -2,13 +2,9 @@ /* * Copyright (c) by Lee Revell <rlrevell@joe-job.com> * Clemens Ladisch <clemens@ladisch.de> - * Routines for control of EMU10K1 chips - * - * BUGS: - * -- + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> * - * TODO: - * -- + * Routines for control of EMU10K1 chips */ #include <linux/time.h> @@ -18,46 +14,56 @@ 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; } +static unsigned long snd_emu10k1_timer_c_resolution(struct snd_timer *timer) +{ + struct snd_emu10k1 *emu = snd_timer_chip(timer); + + if (emu->card_capabilities->emu_model && + emu->emu1010.word_clock == 44100) + return 22676; // 1 sample @ 44.1 kHz = 22.675736...us + else + return 20833; // 1 sample @ 48 kHz = 20.833...us +} + static int snd_emu10k1_timer_precise_resolution(struct snd_timer *timer, unsigned long *num, unsigned long *den) { + struct snd_emu10k1 *emu = snd_timer_chip(timer); + *num = 1; - *den = 48000; + if (emu->card_capabilities->emu_model) + *den = emu->emu1010.word_clock; + else + *den = 48000; return 0; } static const struct snd_timer_hardware snd_emu10k1_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, - .resolution = 20833, /* 1 sample @ 48KHZ = 20.833...us */ .ticks = 1024, .start = snd_emu10k1_timer_start, .stop = snd_emu10k1_timer_stop, + .c_resolution = snd_emu10k1_timer_c_resolution, .precise_resolution = snd_emu10k1_timer_precise_resolution, }; @@ -72,7 +78,8 @@ int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) tid.card = emu->card->number; tid.device = device; tid.subdevice = 0; - if ((err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer)) >= 0) { + err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer); + if (err >= 0) { strcpy(timer->name, "EMU10K1 timer"); timer->private_data = emu; timer->hw = snd_emu10k1_timer_hw; diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h index 7fd235345292..e3fcb290271c 100644 --- a/sound/pci/emu10k1/tina2.h +++ b/sound/pci/emu10k1/tina2.h @@ -2,7 +2,6 @@ /* * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> * Driver tina2 chips - * Version: 0.1 */ /********************************************************************************************************/ diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index cbeb8443492c..77fb5427aaed 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -1,17 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * Creative Labs, Inc. * Lee Revell <rlrevell@joe-job.com> - * Routines for control of EMU10K1 chips - voice manager - * - * Rewrote voice allocator for multichannel support - rlrevell 12/2004 - * - * BUGS: - * -- + * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> + * Creative Labs, Inc. * - * TODO: - * -- + * Routines for control of EMU10K1 chips - voice manager */ #include <linux/time.h> @@ -23,110 +17,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 } -int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number, - struct snd_emu10k1_voice **rvoice) +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 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 +124,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; } |