aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/pci/emu10k1
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/emu10k1')
-rw-r--r--sound/pci/emu10k1/emu10k1.c127
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c257
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c946
-rw-r--r--sound/pci/emu10k1/emu10k1_synth.c11
-rw-r--r--sound/pci/emu10k1/emu10k1x.c194
-rw-r--r--sound/pci/emu10k1/emufx.c952
-rw-r--r--sound/pci/emu10k1/emumixer.c1806
-rw-r--r--sound/pci/emu10k1/emumpu401.c52
-rw-r--r--sound/pci/emu10k1/emupcm.c1155
-rw-r--r--sound/pci/emu10k1/emuproc.c542
-rw-r--r--sound/pci/emu10k1/io.c423
-rw-r--r--sound/pci/emu10k1/irq.c81
-rw-r--r--sound/pci/emu10k1/memory.c29
-rw-r--r--sound/pci/emu10k1/p16v.c177
-rw-r--r--sound/pci/emu10k1/p16v.h58
-rw-r--r--sound/pci/emu10k1/p17v.h5
-rw-r--r--sound/pci/emu10k1/timer.c37
-rw-r--r--sound/pci/emu10k1/tina2.h1
-rw-r--r--sound/pci/emu10k1/voice.c148
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, &reg); /* 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, &reg);
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, &reg);
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg);
- 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, &reg);
- 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, &reg); // 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", &reg, &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", &reg, &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;
}