summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/aoa/codecs/onyx.c8
-rw-r--r--sound/aoa/codecs/tas.c10
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c6
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c4
-rw-r--r--sound/atmel/abdac.c18
-rw-r--r--sound/atmel/ac97c.c12
-rw-r--r--sound/core/Makefile3
-rw-r--r--sound/core/control.c71
-rw-r--r--sound/core/init.c33
-rw-r--r--sound/core/pcm.c48
-rw-r--r--sound/core/pcm_lib.c148
-rw-r--r--sound/core/pcm_native.c214
-rw-r--r--sound/core/pcm_trace.h110
-rw-r--r--sound/core/seq/oss/seq_oss_init.c9
-rw-r--r--sound/core/seq/seq.c5
-rw-r--r--sound/core/seq/seq_device.c103
-rw-r--r--sound/core/sgbuf.c3
-rw-r--r--sound/core/sound.c9
-rw-r--r--sound/drivers/mts64.c18
-rw-r--r--sound/drivers/virmidi.c21
-rw-r--r--sound/drivers/vx/vx_core.c10
-rw-r--r--sound/drivers/vx/vx_mixer.c35
-rw-r--r--sound/firewire/Kconfig26
-rw-r--r--sound/firewire/Makefile7
-rw-r--r--sound/firewire/amdtp.c8
-rw-r--r--sound/firewire/amdtp.h24
-rw-r--r--sound/firewire/bebob/bebob.h4
-rw-r--r--sound/firewire/bebob/bebob_focusrite.c10
-rw-r--r--sound/firewire/bebob/bebob_maudio.c59
-rw-r--r--sound/firewire/bebob/bebob_terratec.c4
-rw-r--r--sound/firewire/bebob/bebob_yamaha.c2
-rw-r--r--sound/firewire/cmp.c2
-rw-r--r--sound/firewire/dice.c1511
-rw-r--r--sound/firewire/dice/Makefile3
-rw-r--r--sound/firewire/dice/dice-hwdep.c190
-rw-r--r--sound/firewire/dice/dice-interface.h (renamed from sound/firewire/dice-interface.h)0
-rw-r--r--sound/firewire/dice/dice-midi.c157
-rw-r--r--sound/firewire/dice/dice-pcm.c422
-rw-r--r--sound/firewire/dice/dice-proc.c252
-rw-r--r--sound/firewire/dice/dice-stream.c407
-rw-r--r--sound/firewire/dice/dice-transaction.c382
-rw-r--r--sound/firewire/dice/dice.c361
-rw-r--r--sound/firewire/dice/dice.h189
-rw-r--r--sound/firewire/isight.c10
-rw-r--r--sound/firewire/oxfw/Makefile3
-rw-r--r--sound/firewire/oxfw/oxfw-command.c153
-rw-r--r--sound/firewire/oxfw/oxfw-control.c283
-rw-r--r--sound/firewire/oxfw/oxfw-hwdep.c190
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c207
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c424
-rw-r--r--sound/firewire/oxfw/oxfw-proc.c113
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c686
-rw-r--r--sound/firewire/oxfw/oxfw.c317
-rw-r--r--sound/firewire/oxfw/oxfw.h146
-rw-r--r--sound/firewire/speakers.c792
-rw-r--r--sound/i2c/other/ak4xxx-adda.c26
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c10
-rw-r--r--sound/isa/es1688/es1688_lib.c13
-rw-r--r--sound/isa/es18xx.c78
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c11
-rw-r--r--sound/isa/sb/emu8000_synth.c3
-rw-r--r--sound/isa/sb/sb16_main.c10
-rw-r--r--sound/isa/sb/sb_common.c3
-rw-r--r--sound/isa/sb/sb_mixer.c31
-rw-r--r--sound/isa/wss/wss_lib.c16
-rw-r--r--sound/mips/sgio2audio.c11
-rw-r--r--sound/oss/uart401.c11
-rw-r--r--sound/parisc/harmony.c12
-rw-r--r--sound/pci/ac97/ac97_codec.c10
-rw-r--r--sound/pci/ac97/ac97_patch.c198
-rw-r--r--sound/pci/ac97/ac97_patch.h2
-rw-r--r--sound/pci/asihpi/asihpi.c377
-rw-r--r--sound/pci/asihpi/hpi.h16
-rw-r--r--sound/pci/asihpi/hpi6205.c43
-rw-r--r--sound/pci/asihpi/hpi_internal.h20
-rw-r--r--sound/pci/asihpi/hpicmn.c107
-rw-r--r--sound/pci/asihpi/hpicmn.h19
-rw-r--r--sound/pci/asihpi/hpimsginit.c30
-rw-r--r--sound/pci/asihpi/hpimsgx.c15
-rw-r--r--sound/pci/asihpi/hpioctl.c126
-rw-r--r--sound/pci/asihpi/hpios.h8
-rw-r--r--sound/pci/atiixp.c4
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/au88x0/au88x0.c35
-rw-r--r--sound/pci/au88x0/au88x0.h4
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c21
-rw-r--r--sound/pci/au88x0/au88x0_core.c102
-rw-r--r--sound/pci/au88x0/au88x0_eq.c3
-rw-r--r--sound/pci/au88x0/au88x0_game.c3
-rw-r--r--sound/pci/au88x0/au88x0_mpu401.c2
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c8
-rw-r--r--sound/pci/au88x0/au88x0_synth.c17
-rw-r--r--sound/pci/aw2/aw2-alsa.c13
-rw-r--r--sound/pci/azt3328.c13
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c40
-rw-r--r--sound/pci/ctxfi/ctatc.c10
-rw-r--r--sound/pci/ctxfi/ctdaio.c30
-rw-r--r--sound/pci/ctxfi/cttimer.c4
-rw-r--r--sound/pci/echoaudio/darla20_dsp.c5
-rw-r--r--sound/pci/echoaudio/darla24_dsp.c13
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c5
-rw-r--r--sound/pci/echoaudio/echoaudio.c145
-rw-r--r--sound/pci/echoaudio/echoaudio.h31
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c27
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c109
-rw-r--r--sound/pci/echoaudio/echoaudio_gml.c11
-rw-r--r--sound/pci/echoaudio/gina20_dsp.c9
-rw-r--r--sound/pci/echoaudio/gina24_dsp.c30
-rw-r--r--sound/pci/echoaudio/indigo_dsp.c11
-rw-r--r--sound/pci/echoaudio/indigo_express_dsp.c6
-rw-r--r--sound/pci/echoaudio/indigodj_dsp.c11
-rw-r--r--sound/pci/echoaudio/indigodjx_dsp.c5
-rw-r--r--sound/pci/echoaudio/indigoio_dsp.c8
-rw-r--r--sound/pci/echoaudio/indigoiox_dsp.c5
-rw-r--r--sound/pci/echoaudio/layla20_dsp.c28
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c26
-rw-r--r--sound/pci/echoaudio/mia_dsp.c15
-rw-r--r--sound/pci/echoaudio/midi.c23
-rw-r--r--sound/pci/echoaudio/mona_dsp.c29
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c9
-rw-r--r--sound/pci/emu10k1/emu10k1x.c2
-rw-r--r--sound/pci/emu10k1/emufx.c3
-rw-r--r--sound/pci/emu10k1/emumixer.c58
-rw-r--r--sound/pci/emu10k1/p16v.c20
-rw-r--r--sound/pci/es1938.c10
-rw-r--r--sound/pci/es1968.c15
-rw-r--r--sound/pci/fm801.c10
-rw-r--r--sound/pci/hda/hda_auto_parser.c66
-rw-r--r--sound/pci/hda/hda_beep.c38
-rw-r--r--sound/pci/hda/hda_codec.c298
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/hda_generic.c191
-rw-r--r--sound/pci/hda/hda_generic.h9
-rw-r--r--sound/pci/hda/hda_intel.c150
-rw-r--r--sound/pci/hda/hda_jack.c60
-rw-r--r--sound/pci/hda/hda_jack.h5
-rw-r--r--sound/pci/hda/hda_priv.h16
-rw-r--r--sound/pci/hda/hda_sysfs.c35
-rw-r--r--sound/pci/hda/patch_analog.c5
-rw-r--r--sound/pci/hda/patch_ca0132.c11
-rw-r--r--sound/pci/hda/patch_conexant.c4
-rw-r--r--sound/pci/hda/patch_hdmi.c6
-rw-r--r--sound/pci/hda/patch_realtek.c109
-rw-r--r--sound/pci/hda/patch_via.c2
-rw-r--r--sound/pci/ice1712/aureon.c46
-rw-r--r--sound/pci/ice1712/ews.c16
-rw-r--r--sound/pci/ice1712/hoontech.c6
-rw-r--r--sound/pci/ice1712/ice1712.c52
-rw-r--r--sound/pci/ice1712/ice1724.c18
-rw-r--r--sound/pci/ice1712/juli.c5
-rw-r--r--sound/pci/ice1712/maya44.c20
-rw-r--r--sound/pci/ice1712/phase.c12
-rw-r--r--sound/pci/ice1712/pontis.c8
-rw-r--r--sound/pci/ice1712/prodigy192.c22
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c11
-rw-r--r--sound/pci/ice1712/quartet.c32
-rw-r--r--sound/pci/ice1712/revo.c4
-rw-r--r--sound/pci/ice1712/se.c9
-rw-r--r--sound/pci/korg1212/korg1212.c26
-rw-r--r--sound/pci/lola/lola.c2
-rw-r--r--sound/pci/lola/lola_mixer.c3
-rw-r--r--sound/pci/lx6464es/lx_defs.h2
-rw-r--r--sound/pci/mixart/mixart_hwdep.c9
-rw-r--r--sound/pci/pcxhr/pcxhr.c54
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c10
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c18
-rw-r--r--sound/pci/rme32.c34
-rw-r--r--sound/pci/rme96.c62
-rw-r--r--sound/pci/rme9652/hdsp.c178
-rw-r--r--sound/pci/rme9652/hdspm.c84
-rw-r--r--sound/pci/rme9652/rme9652.c58
-rw-r--r--sound/pci/sonicvibes.c10
-rw-r--r--sound/pci/trident/trident_main.c3
-rw-r--r--sound/pci/via82xx.c10
-rw-r--r--sound/pci/vx222/vx222_ops.c5
-rw-r--r--sound/pcmcia/vx/vxpocket.c1
-rw-r--r--sound/ppc/pmac.c3
-rw-r--r--sound/ppc/tumbler.c11
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c4
-rw-r--r--sound/soc/fsl/fsl_dma.c9
-rw-r--r--sound/sparc/cs4231.c12
-rw-r--r--sound/usb/6fire/control.c22
-rw-r--r--sound/usb/6fire/firmware.c2
-rw-r--r--sound/usb/6fire/pcm.c17
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/card.c109
-rw-r--r--sound/usb/endpoint.c16
-rw-r--r--sound/usb/endpoint.h2
-rw-r--r--sound/usb/midi.c2
-rw-r--r--sound/usb/misc/ua101.c18
-rw-r--r--sound/usb/mixer.c241
-rw-r--r--sound/usb/mixer.h40
-rw-r--r--sound/usb/mixer_maps.c9
-rw-r--r--sound/usb/mixer_quirks.c920
-rw-r--r--sound/usb/mixer_scarlett.c1004
-rw-r--r--sound/usb/mixer_scarlett.h6
-rw-r--r--sound/usb/pcm.c5
-rw-r--r--sound/usb/quirks-table.h132
-rw-r--r--sound/usb/quirks.c72
-rw-r--r--sound/usb/quirks.h3
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c9
201 files changed, 9507 insertions, 5439 deletions
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 401107b85d30..23c371ecfb6b 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -243,13 +243,7 @@ static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[] = { "Line-In", "Microphone" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index cf3c6303b7e3..364c7c4416e8 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -478,15 +478,9 @@ static struct snd_kcontrol_new drc_switch_control = {
static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Line-In", "Microphone" };
+ static const char * const texts[] = { "Line-In", "Microphone" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index a80d5ea87ccd..4e2b4fbf2496 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -79,8 +79,7 @@ static void i2sbus_release_dev(struct device *dev)
if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
- if (i2sdev->allocated_resource[i])
- release_and_free_resource(i2sdev->allocated_resource[i]);
+ release_and_free_resource(i2sdev->allocated_resource[i]);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
@@ -323,8 +322,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
if (dev->out.dbdma) iounmap(dev->out.dbdma);
if (dev->in.dbdma) iounmap(dev->in.dbdma);
for (i=0;i<3;i++)
- if (dev->allocated_resource[i])
- release_and_free_resource(dev->allocated_resource[i]);
+ release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
kfree(dev);
return 0;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index a61d7a9a995e..01f8fdc42b1b 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -200,9 +200,7 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
} else {
printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
dma_ch, dcsr);
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stop_xrun(substream);
}
}
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 31061e3521d4..023140504104 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -242,7 +242,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- clk_enable(dac->sample_clk);
+ clk_prepare_enable(dac->sample_clk);
retval = dw_dma_cyclic_start(dac->dma.chan);
if (retval)
goto out;
@@ -254,7 +254,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
dw_dma_cyclic_stop(dac->dma.chan);
dac_writel(dac, DATA, 0);
dac_writel(dac, CTRL, 0);
- clk_disable(dac->sample_clk);
+ clk_disable_unprepare(dac->sample_clk);
break;
default:
retval = -EINVAL;
@@ -429,7 +429,7 @@ static int atmel_abdac_probe(struct platform_device *pdev)
retval = PTR_ERR(sample_clk);
goto out_put_pclk;
}
- clk_enable(pclk);
+ clk_prepare_enable(pclk);
retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -528,7 +528,7 @@ out_free_card:
snd_card_free(card);
out_put_sample_clk:
clk_put(sample_clk);
- clk_disable(pclk);
+ clk_disable_unprepare(pclk);
out_put_pclk:
clk_put(pclk);
return retval;
@@ -541,8 +541,8 @@ static int atmel_abdac_suspend(struct device *pdev)
struct atmel_abdac *dac = card->private_data;
dw_dma_cyclic_stop(dac->dma.chan);
- clk_disable(dac->sample_clk);
- clk_disable(dac->pclk);
+ clk_disable_unprepare(dac->sample_clk);
+ clk_disable_unprepare(dac->pclk);
return 0;
}
@@ -552,8 +552,8 @@ static int atmel_abdac_resume(struct device *pdev)
struct snd_card *card = dev_get_drvdata(pdev);
struct atmel_abdac *dac = card->private_data;
- clk_enable(dac->pclk);
- clk_enable(dac->sample_clk);
+ clk_prepare_enable(dac->pclk);
+ clk_prepare_enable(dac->sample_clk);
if (test_bit(DMA_READY, &dac->flags))
dw_dma_cyclic_start(dac->dma.chan);
@@ -572,7 +572,7 @@ static int atmel_abdac_remove(struct platform_device *pdev)
struct atmel_abdac *dac = get_dac(card);
clk_put(dac->sample_clk);
- clk_disable(dac->pclk);
+ clk_disable_unprepare(dac->pclk);
clk_put(dac->pclk);
dma_release_channel(dac->dma.chan);
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index b59427d5a697..cb44c74c9702 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -773,7 +773,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
return err;
}
retval = snd_pcm_new(chip->card, chip->card->shortname,
- chip->pdev->id, playback, capture, &pcm);
+ 0, playback, capture, &pcm);
if (retval)
return retval;
@@ -944,7 +944,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
- clk_enable(pclk);
+ clk_prepare_enable(pclk);
retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -1122,7 +1122,7 @@ err_ioremap:
err_request_irq:
snd_card_free(card);
err_snd_card_new:
- clk_disable(pclk);
+ clk_disable_unprepare(pclk);
clk_put(pclk);
return retval;
}
@@ -1139,7 +1139,7 @@ static int atmel_ac97c_suspend(struct device *pdev)
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
}
- clk_disable(chip->pclk);
+ clk_disable_unprepare(chip->pclk);
return 0;
}
@@ -1149,7 +1149,7 @@ static int atmel_ac97c_resume(struct device *pdev)
struct snd_card *card = dev_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
- clk_enable(chip->pclk);
+ clk_prepare_enable(chip->pclk);
if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
@@ -1177,7 +1177,7 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
ac97c_writel(chip, COMR, 0);
ac97c_writel(chip, MR, 0);
- clk_disable(chip->pclk);
+ clk_disable_unprepare(chip->pclk);
clk_put(chip->pclk);
iounmap(chip->regs);
free_irq(chip->irq, chip);
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 394a38909f6b..4daf2f58261c 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o memalloc.o
snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
+# for trace-points
+CFLAGS_pcm_lib.o := -I$(src)
+
snd-pcm-dmaengine-objs := pcm_dmaengine.o
snd-rawmidi-objs := rawmidi.o
diff --git a/sound/core/control.c b/sound/core/control.c
index b9611344ff9e..bb96a467e88d 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -141,6 +141,16 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
return 0;
}
+/**
+ * snd_ctl_notify - Send notification to user-space for a control change
+ * @card: the card to send notification
+ * @mask: the event mask, SNDRV_CTL_EVENT_*
+ * @id: the ctl element id to send notification
+ *
+ * This function adds an event record with the given id and mask, appends
+ * to the list and wakes up the user-space for notification. This can be
+ * called in the atomic context.
+ */
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
@@ -179,7 +189,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
}
read_unlock(&card->ctl_files_rwlock);
}
-
EXPORT_SYMBOL(snd_ctl_notify);
/**
@@ -261,7 +270,6 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
kctl.private_data = private_data;
return snd_ctl_new(&kctl, access);
}
-
EXPORT_SYMBOL(snd_ctl_new1);
/**
@@ -280,7 +288,6 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
kfree(kcontrol);
}
}
-
EXPORT_SYMBOL(snd_ctl_free_one);
static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
@@ -376,7 +383,6 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_free_one(kcontrol);
return err;
}
-
EXPORT_SYMBOL(snd_ctl_add);
/**
@@ -471,7 +477,6 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_free_one(kcontrol);
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_remove);
/**
@@ -499,7 +504,6 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
up_write(&card->controls_rwsem);
return ret;
}
-
EXPORT_SYMBOL(snd_ctl_remove_id);
/**
@@ -568,7 +572,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
ret = -ENOENT;
goto unlock;
}
- index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
+ index_offset = snd_ctl_get_ioff(kctl, id);
vd = &kctl->vd[index_offset];
ret = 0;
if (active) {
@@ -617,7 +621,6 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
up_write(&card->controls_rwsem);
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_rename_id);
/**
@@ -645,7 +648,6 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi
}
return NULL;
}
-
EXPORT_SYMBOL(snd_ctl_find_numid);
/**
@@ -687,7 +689,6 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
}
return NULL;
}
-
EXPORT_SYMBOL(snd_ctl_find_id);
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
@@ -1526,19 +1527,28 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
return 0;
}
+/**
+ * snd_ctl_register_ioctl - register the device-specific control-ioctls
+ * @fcn: ioctl callback function
+ *
+ * called from each device manager like pcm.c, hwdep.c, etc.
+ */
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_register_ioctl);
#ifdef CONFIG_COMPAT
+/**
+ * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat
+ * control-ioctls
+ * @fcn: ioctl callback function
+ */
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
#endif
@@ -1566,19 +1576,26 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
return -EINVAL;
}
+/**
+ * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls
+ * @fcn: ioctl callback function to unregister
+ */
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
#ifdef CONFIG_COMPAT
+/**
+ * snd_ctl_unregister_ioctl - de-register the device-specific compat 32bit
+ * control-ioctls
+ * @fcn: ioctl callback function to unregister
+ */
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
#endif
@@ -1702,6 +1719,16 @@ int snd_ctl_create(struct snd_card *card)
/*
* Frequently used control callbacks/helpers
*/
+
+/**
+ * snd_ctl_boolean_mono_info - Helper function for a standard boolean info
+ * callback with a mono channel
+ * @kcontrol: the kcontrol instance
+ * @uinfo: info to store
+ *
+ * This is a function that can be used as info callback for a standard
+ * boolean control with a single mono channel.
+ */
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1711,9 +1738,17 @@ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
+/**
+ * snd_ctl_boolean_stereo_info - Helper function for a standard boolean info
+ * callback with stereo two channels
+ * @kcontrol: the kcontrol instance
+ * @uinfo: info to store
+ *
+ * This is a function that can be used as info callback for a standard
+ * boolean control with stereo two channels.
+ */
int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1723,7 +1758,6 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
/**
@@ -1745,8 +1779,13 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = channels;
info->value.enumerated.items = items;
+ if (!items)
+ return 0;
if (info->value.enumerated.item >= items)
info->value.enumerated.item = items - 1;
+ WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name),
+ "ALSA: too long item name '%s'\n",
+ names[info->value.enumerated.item]);
strlcpy(info->value.enumerated.name,
names[info->value.enumerated.item],
sizeof(info->value.enumerated.name));
diff --git a/sound/core/init.c b/sound/core/init.c
index 7bdfd19e24a8..074875d68c15 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -438,17 +438,6 @@ int snd_card_disconnect(struct snd_card *card)
EXPORT_SYMBOL(snd_card_disconnect);
-/**
- * snd_card_free - frees given soundcard structure
- * @card: soundcard structure
- *
- * This function releases the soundcard structure and the all assigned
- * devices automatically. That is, you don't have to release the devices
- * by yourself.
- *
- * Return: Zero. Frees all associated devices and frees the control
- * interface associated to given soundcard.
- */
static int snd_card_do_free(struct snd_card *card)
{
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@@ -469,6 +458,15 @@ static int snd_card_do_free(struct snd_card *card)
return 0;
}
+/**
+ * snd_card_free_when_closed - Disconnect the card, free it later eventually
+ * @card: soundcard structure
+ *
+ * Unlike snd_card_free(), this function doesn't try to release the card
+ * resource immediately, but tries to disconnect at first. When the card
+ * is still in use, the function returns before freeing the resources.
+ * The card resources will be freed when the refcount gets to zero.
+ */
int snd_card_free_when_closed(struct snd_card *card)
{
int ret = snd_card_disconnect(card);
@@ -479,6 +477,19 @@ int snd_card_free_when_closed(struct snd_card *card)
}
EXPORT_SYMBOL(snd_card_free_when_closed);
+/**
+ * snd_card_free - frees given soundcard structure
+ * @card: soundcard structure
+ *
+ * This function releases the soundcard structure and the all assigned
+ * devices automatically. That is, you don't have to release the devices
+ * by yourself.
+ *
+ * This function waits until the all resources are properly released.
+ *
+ * Return: Zero. Frees all associated devices and frees the control
+ * interface associated to given soundcard.
+ */
int snd_card_free(struct snd_card *card)
{
struct completion released;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index c6ff94ab1ad6..cfc56c806964 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -220,6 +220,10 @@ static char *snd_pcm_format_names[] = {
FORMAT(DSD_U32_BE),
};
+/**
+ * snd_pcm_format_name - Return a name string for the given PCM format
+ * @format: PCM format
+ */
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
@@ -481,6 +485,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_pcm_runtime *runtime;
+
+ snd_pcm_stream_lock_irq(substream);
+ runtime = substream->runtime;
+ if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irq(substream);
+}
+
static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -612,6 +629,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
}
substream->proc_status_entry = entry;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ entry = snd_info_create_card_entry(card, "xrun_injection",
+ substream->proc_root);
+ if (entry) {
+ entry->private_data = substream;
+ entry->c.text.read = NULL;
+ entry->c.text.write = snd_pcm_xrun_injection_write;
+ entry->mode = S_IFREG | S_IWUSR;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ }
+ substream->proc_xrun_injection_entry = entry;
+#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
+
return 0;
}
@@ -625,6 +658,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
substream->proc_sw_params_entry = NULL;
snd_info_free_entry(substream->proc_status_entry);
substream->proc_status_entry = NULL;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ snd_info_free_entry(substream->proc_xrun_injection_entry);
+ substream->proc_xrun_injection_entry = NULL;
+#endif
snd_info_free_entry(substream->proc_root);
substream->proc_root = NULL;
return 0;
@@ -709,7 +746,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
}
return 0;
}
-
EXPORT_SYMBOL(snd_pcm_new_stream);
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
@@ -1157,6 +1193,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
return 0;
}
+/**
+ * snd_pcm_notify - Add/remove the notify list
+ * @notify: PCM notify list
+ * @nfree: 0 = register, 1 = unregister
+ *
+ * This adds the given notifier to the global list so that the callback is
+ * called for each registered PCM devices. This exists only for PCM OSS
+ * emulation, so far.
+ */
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
struct snd_pcm *pcm;
@@ -1179,7 +1224,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
mutex_unlock(&register_mutex);
return 0;
}
-
EXPORT_SYMBOL(snd_pcm_notify);
#ifdef CONFIG_PROC_FS
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index dfc28542a007..ec9e7866177f 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -32,6 +32,15 @@
#include <sound/pcm_params.h>
#include <sound/timer.h>
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define CREATE_TRACE_POINTS
+#include "pcm_trace.h"
+#else
+#define trace_hwptr(substream, pos, in_interrupt)
+#define trace_xrun(substream)
+#define trace_hw_ptr_error(substream, reason)
+#endif
+
/*
* fill ring buffer with silence
* runtime->silence_start: starting pointer to silence area
@@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name);
#define XRUN_DEBUG_BASIC (1<<0)
#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
-#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
-#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
-#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
-#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ trace_xrun(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
@@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream)
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-#define hw_ptr_error(substream, fmt, args...) \
+#define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \
do { \
+ trace_hw_ptr_error(substream, reason); \
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
- xrun_log_show(substream); \
- pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \
+ pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \
+ (in_interrupt) ? 'Q' : 'P', ##args); \
dump_stack_on_xrun(substream); \
} \
} while (0)
-#define XRUN_LOG_CNT 10
-
-struct hwptr_log_entry {
- unsigned int in_interrupt;
- unsigned long jiffies;
- snd_pcm_uframes_t pos;
- snd_pcm_uframes_t period_size;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_uframes_t old_hw_ptr;
- snd_pcm_uframes_t hw_ptr_base;
-};
-
-struct snd_pcm_hwptr_log {
- unsigned int idx;
- unsigned int hit: 1;
- struct hwptr_log_entry entries[XRUN_LOG_CNT];
-};
-
-static void xrun_log(struct snd_pcm_substream *substream,
- snd_pcm_uframes_t pos, int in_interrupt)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
- struct hwptr_log_entry *entry;
-
- if (log == NULL) {
- log = kzalloc(sizeof(*log), GFP_ATOMIC);
- if (log == NULL)
- return;
- runtime->hwptr_log = log;
- } else {
- if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
- return;
- }
- entry = &log->entries[log->idx];
- entry->in_interrupt = in_interrupt;
- entry->jiffies = jiffies;
- entry->pos = pos;
- entry->period_size = runtime->period_size;
- entry->buffer_size = runtime->buffer_size;
- entry->old_hw_ptr = runtime->status->hw_ptr;
- entry->hw_ptr_base = runtime->hw_ptr_base;
- log->idx = (log->idx + 1) % XRUN_LOG_CNT;
-}
-
-static void xrun_log_show(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
- struct hwptr_log_entry *entry;
- char name[16];
- unsigned int idx;
- int cnt;
-
- if (log == NULL)
- return;
- if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
- return;
- snd_pcm_debug_name(substream, name, sizeof(name));
- for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
- entry = &log->entries[idx];
- if (entry->period_size == 0)
- break;
- pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
- "hwptr=%ld/%ld\n",
- name, entry->in_interrupt ? "[Q] " : "",
- entry->jiffies,
- (unsigned long)entry->pos,
- (unsigned long)entry->period_size,
- (unsigned long)entry->buffer_size,
- (unsigned long)entry->old_hw_ptr,
- (unsigned long)entry->hw_ptr_base);
- idx++;
- idx %= XRUN_LOG_CNT;
- }
- log->hit = 1;
-}
-
#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
#define hw_ptr_error(substream, fmt, args...) do { } while (0)
-#define xrun_log(substream, pos, in_interrupt) do { } while (0)
-#define xrun_log_show(substream) do { } while (0)
#endif
@@ -343,17 +271,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
if (printk_ratelimit()) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- xrun_log_show(substream);
pcm_err(substream->pcm,
- "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+ "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
name, pos, runtime->buffer_size,
runtime->period_size);
}
pos = 0;
}
pos -= pos % runtime->min_align;
- if (xrun_debug(substream, XRUN_DEBUG_LOG))
- xrun_log(substream, pos, in_interrupt);
+ trace_hwptr(substream, pos, in_interrupt);
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
if (in_interrupt) {
@@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
delta = new_hw_ptr - old_hw_ptr;
if (delta < 0)
delta += runtime->boundary;
- if (xrun_debug(substream, in_interrupt ?
- XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
- char name[16];
- snd_pcm_debug_name(substream, name, sizeof(name));
- pcm_dbg(substream->pcm,
- "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n",
- in_interrupt ? "period" : "hwptr",
- name,
- (unsigned int)pos,
- (unsigned int)runtime->period_size,
- (unsigned int)runtime->buffer_size,
- (unsigned long)delta,
- (unsigned long)old_hw_ptr,
- (unsigned long)new_hw_ptr,
- (unsigned long)runtime->hw_ptr_base);
- }
if (runtime->no_period_wakeup) {
snd_pcm_sframes_t xrun_threshold;
@@ -431,13 +341,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* something must be really wrong */
if (delta >= runtime->buffer_size + runtime->period_size) {
- hw_ptr_error(substream,
- "Unexpected hw_pointer value %s"
- "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
- "old_hw_ptr=%ld)\n",
- in_interrupt ? "[Q] " : "[P]",
- substream->stream, (long)pos,
- (long)new_hw_ptr, (long)old_hw_ptr);
+ hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr",
+ "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
+ substream->stream, (long)pos,
+ (long)new_hw_ptr, (long)old_hw_ptr);
return 0;
}
@@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
delta--;
}
/* align hw_base to buffer_size */
- hw_ptr_error(substream,
- "hw_ptr skipping! %s"
- "(pos=%ld, delta=%ld, period=%ld, "
- "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
- in_interrupt ? "[Q] " : "",
+ hw_ptr_error(substream, in_interrupt, "hw_ptr skipping",
+ "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
(long)pos, (long)hdelta,
(long)runtime->period_size, jdelta,
((hdelta * HZ) / runtime->rate), hw_base,
@@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
no_jiffies_check:
if (delta > runtime->period_size + runtime->period_size / 2) {
- hw_ptr_error(substream,
- "Lost interrupts? %s"
- "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
- "old_hw_ptr=%ld)\n",
- in_interrupt ? "[Q] " : "",
+ hw_ptr_error(substream, in_interrupt,
+ "Lost interrupts?",
+ "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
substream->stream, (long)delta,
(long)new_hw_ptr,
(long)old_hw_ptr);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 166d59cdc86b..095d9572ad2b 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -35,9 +35,6 @@
#include <sound/timer.h>
#include <sound/minors.h>
#include <asm/io.h>
-#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
-#include <dma-coherence.h>
-#endif
/*
* Compatibility
@@ -77,6 +74,14 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
static DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
+/**
+ * snd_pcm_stream_lock - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream's spinlock or mutex depending on the nonatomic
+ * flag of the given substream. This also takes the global link rw lock
+ * (or rw sem), too, for avoiding the race with linked streams.
+ */
void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
{
if (substream->pcm->nonatomic) {
@@ -89,6 +94,12 @@ void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
+/**
+ * snd_pcm_stream_lock - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock().
+ */
void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
{
if (substream->pcm->nonatomic) {
@@ -101,6 +112,14 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
+/**
+ * snd_pcm_stream_lock_irq - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock() and disables the local
+ * IRQ (only when nonatomic is false). In nonatomic case, this is identical
+ * as snd_pcm_stream_lock().
+ */
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
{
if (!substream->pcm->nonatomic)
@@ -109,6 +128,12 @@ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
+/**
+ * snd_pcm_stream_unlock_irq - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irq().
+ */
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
{
snd_pcm_stream_unlock(substream);
@@ -127,6 +152,13 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
+/**
+ * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irqsave().
+ */
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags)
{
@@ -195,6 +227,21 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
return err;
}
+static bool hw_support_mmap(struct snd_pcm_substream *substream)
+{
+ if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
+ return false;
+ /* check architectures that return -EINVAL from dma_mmap_coherent() */
+ /* FIXME: this should be some global flag */
+#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\
+ defined(CONFIG_PARISC) || defined(CONFIG_XTENSA)
+ if (!substream->ops->mmap &&
+ substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+ return false;
+#endif
+ return true;
+}
+
#undef RULES_DEBUG
#ifdef RULES_DEBUG
@@ -372,8 +419,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
}
hw = &substream->runtime->hw;
- if (!params->info)
+ if (!params->info) {
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ if (!hw_support_mmap(substream))
+ params->info &= ~(SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID);
+ }
if (!params->fifo_size) {
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
@@ -849,14 +900,19 @@ static int snd_pcm_action_single(struct action_ops *ops,
return res;
}
-/* call in mutex-protected context */
-static int snd_pcm_action_mutex(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
+/*
+ * Note: call with stream lock
+ */
+static int snd_pcm_action(struct action_ops *ops,
+ struct snd_pcm_substream *substream,
+ int state)
{
int res;
- if (snd_pcm_stream_linked(substream)) {
+ if (!snd_pcm_stream_linked(substream))
+ return snd_pcm_action_single(ops, substream, state);
+
+ if (substream->pcm->nonatomic) {
if (!mutex_trylock(&substream->group->mutex)) {
mutex_unlock(&substream->self_group.mutex);
mutex_lock(&substream->group->mutex);
@@ -865,24 +921,6 @@ static int snd_pcm_action_mutex(struct action_ops *ops,
res = snd_pcm_action_group(ops, substream, state, 1);
mutex_unlock(&substream->group->mutex);
} else {
- res = snd_pcm_action_single(ops, substream, state);
- }
- return res;
-}
-
-/*
- * Note: call with stream lock
- */
-static int snd_pcm_action(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
-{
- int res;
-
- if (substream->pcm->nonatomic)
- return snd_pcm_action_mutex(ops, substream, state);
-
- if (snd_pcm_stream_linked(substream)) {
if (!spin_trylock(&substream->group->lock)) {
spin_unlock(&substream->self_group.lock);
spin_lock(&substream->group->lock);
@@ -890,34 +928,10 @@ static int snd_pcm_action(struct action_ops *ops,
}
res = snd_pcm_action_group(ops, substream, state, 1);
spin_unlock(&substream->group->lock);
- } else {
- res = snd_pcm_action_single(ops, substream, state);
}
return res;
}
-static int snd_pcm_action_lock_mutex(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
-{
- int res;
-
- down_read(&snd_pcm_link_rwsem);
- if (snd_pcm_stream_linked(substream)) {
- mutex_lock(&substream->group->mutex);
- mutex_lock(&substream->self_group.mutex);
- res = snd_pcm_action_group(ops, substream, state, 1);
- mutex_unlock(&substream->self_group.mutex);
- mutex_unlock(&substream->group->mutex);
- } else {
- mutex_lock(&substream->self_group.mutex);
- res = snd_pcm_action_single(ops, substream, state);
- mutex_unlock(&substream->self_group.mutex);
- }
- up_read(&snd_pcm_link_rwsem);
- return res;
-}
-
/*
* Note: don't use any locks before
*/
@@ -927,22 +941,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
{
int res;
- if (substream->pcm->nonatomic)
- return snd_pcm_action_lock_mutex(ops, substream, state);
-
- read_lock_irq(&snd_pcm_link_rwlock);
- if (snd_pcm_stream_linked(substream)) {
- spin_lock(&substream->group->lock);
- spin_lock(&substream->self_group.lock);
- res = snd_pcm_action_group(ops, substream, state, 1);
- spin_unlock(&substream->self_group.lock);
- spin_unlock(&substream->group->lock);
- } else {
- spin_lock(&substream->self_group.lock);
- res = snd_pcm_action_single(ops, substream, state);
- spin_unlock(&substream->self_group.lock);
- }
- read_unlock_irq(&snd_pcm_link_rwlock);
+ snd_pcm_stream_lock_irq(substream);
+ res = snd_pcm_action(ops, substream, state);
+ snd_pcm_stream_unlock_irq(substream);
return res;
}
@@ -1051,10 +1052,10 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state != state) {
snd_pcm_trigger_tstamp(substream);
+ runtime->status->state = state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
&runtime->trigger_tstamp);
- runtime->status->state = state;
}
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
@@ -1097,6 +1098,28 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
SNDRV_PCM_STATE_SETUP);
}
+/**
+ * snd_pcm_stop_xrun - stop the running streams as XRUN
+ * @substream: the PCM substream instance
+ *
+ * This stops the given running substream (and all linked substreams) as XRUN.
+ * Unlike snd_pcm_stop(), this function takes the substream lock by itself.
+ *
+ * Return: Zero if successful, or a negative error code.
+ */
+int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ snd_pcm_stream_lock_irqsave(substream, flags);
+ if (snd_pcm_running(substream))
+ ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irqrestore(substream, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
+
/*
* pause callbacks
*/
@@ -1203,11 +1226,11 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->status->suspended_state = runtime->status->state;
+ runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
&runtime->trigger_tstamp);
- runtime->status->suspended_state = runtime->status->state;
- runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
}
@@ -1310,10 +1333,10 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->status->state = runtime->status->suspended_state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
&runtime->trigger_tstamp);
- runtime->status->state = runtime->status->suspended_state;
}
static struct action_ops snd_pcm_action_resume = {
@@ -2070,7 +2093,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
- if (hw->info & SNDRV_PCM_INFO_MMAP) {
+ if (hw_support_mmap(substream)) {
if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
@@ -3249,20 +3272,6 @@ static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
void *vaddr = substream->runtime->dma_area + ofs;
-#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
- return virt_to_page(CAC_ADDR(vaddr));
-#endif
-#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) {
- dma_addr_t addr = substream->runtime->dma_addr + ofs;
- addr -= get_dma_offset(substream->dma_buffer.dev.dev);
- /* assume dma_handle set via pfn_to_phys() in
- * mm/dma-noncoherent.c
- */
- return pfn_to_page(addr >> PAGE_SHIFT);
- }
-#endif
return virt_to_page(vaddr);
}
@@ -3307,16 +3316,18 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
.fault = snd_pcm_mmap_data_fault,
};
-#ifndef ARCH_HAS_DMA_MMAP_COHERENT
-/* This should be defined / handled globally! */
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-#define ARCH_HAS_DMA_MMAP_COHERENT
-#endif
-#endif
-
/*
* mmap the DMA buffer on RAM
*/
+
+/**
+ * snd_pcm_lib_default_mmap - Default PCM data mmap function
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * This is the default mmap handler for PCM data. When mmap pcm_ops is NULL,
+ * this function is invoked implicitly.
+ */
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
@@ -3329,7 +3340,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
-#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
@@ -3337,11 +3348,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
substream->runtime->dma_area,
substream->runtime->dma_addr,
area->vm_end - area->vm_start);
-#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
- !plat_device_is_coherent(substream->dma_buffer.dev.dev))
- area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
+#endif /* CONFIG_X86 */
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
@@ -3352,6 +3359,15 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
* mmap the DMA buffer on I/O memory area
*/
#if SNDRV_PCM_INFO_MMAP_IOMEM
+/**
+ * snd_pcm_lib_mmap_iomem - Default PCM data mmap function for I/O mem
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * When your hardware uses the iomapped pages as the hardware buffer and
+ * wants to mmap it, pass this function as mmap pcm_ops. Note that this
+ * is supposed to work only on limited architectures.
+ */
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
new file mode 100644
index 000000000000..b63b654da5ff
--- /dev/null
+++ b/sound/core/pcm_trace.h
@@ -0,0 +1,110 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM snd_pcm
+#define TRACE_INCLUDE_FILE pcm_trace
+
+#if !defined(_PCM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _PCM_TRACE_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(hwptr,
+ TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, bool irq),
+ TP_ARGS(substream, pos, irq),
+ TP_STRUCT__entry(
+ __field( bool, in_interrupt )
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( snd_pcm_uframes_t, pos )
+ __field( snd_pcm_uframes_t, period_size )
+ __field( snd_pcm_uframes_t, buffer_size )
+ __field( snd_pcm_uframes_t, old_hw_ptr )
+ __field( snd_pcm_uframes_t, hw_ptr_base )
+ ),
+ TP_fast_assign(
+ __entry->in_interrupt = (irq);
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->pos = (pos);
+ __entry->period_size = (substream)->runtime->period_size;
+ __entry->buffer_size = (substream)->runtime->buffer_size;
+ __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
+ __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number,
+ __entry->in_interrupt ? "IRQ" : "POS",
+ (unsigned long)__entry->pos,
+ (unsigned long)__entry->old_hw_ptr,
+ (unsigned long)__entry->hw_ptr_base,
+ (unsigned long)__entry->period_size,
+ (unsigned long)__entry->buffer_size)
+);
+
+TRACE_EVENT(xrun,
+ TP_PROTO(struct snd_pcm_substream *substream),
+ TP_ARGS(substream),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( snd_pcm_uframes_t, period_size )
+ __field( snd_pcm_uframes_t, buffer_size )
+ __field( snd_pcm_uframes_t, old_hw_ptr )
+ __field( snd_pcm_uframes_t, hw_ptr_base )
+ ),
+ TP_fast_assign(
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->period_size = (substream)->runtime->period_size;
+ __entry->buffer_size = (substream)->runtime->buffer_size;
+ __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
+ __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number,
+ (unsigned long)__entry->old_hw_ptr,
+ (unsigned long)__entry->hw_ptr_base,
+ (unsigned long)__entry->period_size,
+ (unsigned long)__entry->buffer_size)
+);
+
+TRACE_EVENT(hw_ptr_error,
+ TP_PROTO(struct snd_pcm_substream *substream, const char *why),
+ TP_ARGS(substream, why),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( const char *, reason )
+ ),
+ TP_fast_assign(
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->reason = (why);
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number, __entry->reason)
+);
+
+#endif /* _PCM_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index b9184d20c39f..b0e32e161dd1 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -403,14 +403,11 @@ free_devinfo(void *private)
{
struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
- if (dp->timer)
- snd_seq_oss_timer_delete(dp->timer);
+ snd_seq_oss_timer_delete(dp->timer);
- if (dp->writeq)
- snd_seq_oss_writeq_delete(dp->writeq);
+ snd_seq_oss_writeq_delete(dp->writeq);
- if (dp->readq)
- snd_seq_oss_readq_delete(dp->readq);
+ snd_seq_oss_readq_delete(dp->readq);
kfree(dp);
}
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 712110561082..7e0aabb808a6 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void)
{
int err;
- snd_seq_autoload_lock();
if ((err = client_init_data()) < 0)
goto error;
@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void)
if ((err = snd_seq_system_client_init()) < 0)
goto error;
+ snd_seq_autoload_init();
error:
- snd_seq_autoload_unlock();
return err;
}
@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void)
/* release event memory */
snd_sequencer_memory_done();
+
+ snd_seq_autoload_exit();
}
module_init(alsa_seq_init)
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 91a786a783e1..0631bdadd12b 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
#define DRIVER_LOADED (1<<0)
#define DRIVER_REQUESTED (1<<1)
#define DRIVER_LOCKED (1<<2)
+#define DRIVER_REQUESTING (1<<3)
struct ops_list {
char id[ID_LEN]; /* driver id */
@@ -127,42 +128,82 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
#ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */
-static int snd_seq_in_init;
+static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
void snd_seq_autoload_lock(void)
{
- snd_seq_in_init++;
+ atomic_inc(&snd_seq_in_init);
}
void snd_seq_autoload_unlock(void)
{
- snd_seq_in_init--;
+ atomic_dec(&snd_seq_in_init);
}
-#endif
-void snd_seq_device_load_drivers(void)
+static void autoload_drivers(void)
{
-#ifdef CONFIG_MODULES
- struct ops_list *ops;
+ /* avoid reentrance */
+ if (atomic_inc_return(&snd_seq_in_init) == 1) {
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
+ if ((ops->driver & DRIVER_REQUESTING) &&
+ !(ops->driver & DRIVER_REQUESTED)) {
+ ops->used++;
+ mutex_unlock(&ops_mutex);
+ ops->driver |= DRIVER_REQUESTED;
+ request_module("snd-%s", ops->id);
+ mutex_lock(&ops_mutex);
+ ops->used--;
+ }
+ }
+ mutex_unlock(&ops_mutex);
+ }
+ atomic_dec(&snd_seq_in_init);
+}
- /* Calling request_module during module_init()
- * may cause blocking.
- */
- if (snd_seq_in_init)
- return;
+static void call_autoload(struct work_struct *work)
+{
+ autoload_drivers();
+}
- mutex_lock(&ops_mutex);
- list_for_each_entry(ops, &opslist, list) {
- if (! (ops->driver & DRIVER_LOADED) &&
- ! (ops->driver & DRIVER_REQUESTED)) {
- ops->used++;
- mutex_unlock(&ops_mutex);
- ops->driver |= DRIVER_REQUESTED;
- request_module("snd-%s", ops->id);
- mutex_lock(&ops_mutex);
- ops->used--;
- }
+static DECLARE_WORK(autoload_work, call_autoload);
+
+static void try_autoload(struct ops_list *ops)
+{
+ if (!ops->driver) {
+ ops->driver |= DRIVER_REQUESTING;
+ schedule_work(&autoload_work);
}
+}
+
+static void queue_autoload_drivers(void)
+{
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list)
+ try_autoload(ops);
mutex_unlock(&ops_mutex);
+}
+
+void snd_seq_autoload_init(void)
+{
+ atomic_dec(&snd_seq_in_init);
+#ifdef CONFIG_SND_SEQUENCER_MODULE
+ /* initial autoload only when snd-seq is a module */
+ queue_autoload_drivers();
+#endif
+}
+#else
+#define try_autoload(ops) /* NOP */
+#endif
+
+void snd_seq_device_load_drivers(void)
+{
+#ifdef CONFIG_MODULES
+ queue_autoload_drivers();
+ flush_work(&autoload_work);
#endif
}
@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
ops->num_devices++;
mutex_unlock(&ops->reg_mutex);
- unlock_driver(ops);
-
if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
snd_seq_device_free(dev);
return err;
}
+ try_autoload(ops);
+ unlock_driver(ops);
+
if (result)
*result = dev;
@@ -318,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
entry->init_device == NULL || entry->free_device == NULL)
return -EINVAL;
- snd_seq_autoload_lock();
ops = find_driver(id, 1);
- if (ops == NULL) {
- snd_seq_autoload_unlock();
+ if (ops == NULL)
return -ENOMEM;
- }
if (ops->driver & DRIVER_LOADED) {
pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return -EBUSY;
}
@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return 0;
}
@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void)
static void __exit alsa_seq_device_exit(void)
{
+#ifdef CONFIG_MODULES
+ cancel_work_sync(&autoload_work);
+#endif
remove_drivers();
#ifdef CONFIG_PROC_FS
snd_info_free_entry(info_entry);
@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES
+EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index 0a418503ec41..84fffabdd129 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -39,8 +39,7 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
if (! sgbuf)
return -EINVAL;
- if (dmab->area)
- vunmap(dmab->area);
+ vunmap(dmab->area);
dmab->area = NULL;
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 38ad1a0dd3f7..f1333060bf1c 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -355,8 +355,13 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
EXPORT_SYMBOL(snd_unregister_device);
-/* get the assigned device to the given type and device number;
- * the caller needs to release it via put_device() after using it
+/**
+ * snd_get_device - get the assigned device to the given type and device number
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+ * @card:the card instance
+ * @dev: the device index
+ *
+ * The caller needs to release it via put_device() after using it.
*/
struct device *snd_get_device(int type, struct snd_card *card, int dev)
{
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index f5fd448dbc57..0388fbbd2c06 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -604,21 +604,11 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = {
static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = { "24",
- "25",
- "29.97",
- "30D",
- "30" };
+ static const char * const texts[5] = {
+ "24", "25", "29.97", "30D", "30"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl,
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index b178724295f3..d28d8706443c 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -99,30 +99,33 @@ static int snd_virmidi_probe(struct platform_device *devptr)
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
snd_printk(KERN_WARNING
- "too much midi devices for virmidi %d: "
- "force to use %d\n", dev, MAX_MIDI_DEVICES);
+ "too much midi devices for virmidi %d: force to use %d\n",
+ dev, MAX_MIDI_DEVICES);
midi_devs[dev] = MAX_MIDI_DEVICES;
}
for (idx = 0; idx < midi_devs[dev]; idx++) {
struct snd_rawmidi *rmidi;
struct snd_virmidi_dev *rdev;
- if ((err = snd_virmidi_new(card, idx, &rmidi)) < 0)
+
+ err = snd_virmidi_new(card, idx, &rmidi);
+ if (err < 0)
goto __nodev;
rdev = rmidi->private_data;
vmidi->midi[idx] = rmidi;
strcpy(rmidi->name, "Virtual Raw MIDI");
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
}
-
+
strcpy(card->driver, "VirMIDI");
strcpy(card->shortname, "VirMIDI");
sprintf(card->longname, "Virtual MIDI Card %i", dev + 1);
- if ((err = snd_card_register(card)) == 0) {
+ err = snd_card_register(card);
+ if (!err) {
platform_set_drvdata(devptr, card);
return 0;
}
- __nodev:
+__nodev:
snd_card_free(card);
return err;
}
@@ -157,13 +160,15 @@ static int __init alsa_card_virmidi_init(void)
{
int i, cards, err;
- if ((err = platform_driver_register(&snd_virmidi_driver)) < 0)
+ err = platform_driver_register(&snd_virmidi_driver);
+ if (err < 0)
return err;
cards = 0;
for (i = 0; i < SNDRV_CARDS; i++) {
struct platform_device *device;
- if (! enable[i])
+
+ if (!enable[i])
continue;
device = platform_device_register_simple(SND_VIRMIDI_DRIVER,
i, NULL, 0);
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index e8cc16993903..fc05a37fd017 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -416,6 +416,7 @@ int vx_send_rih(struct vx_core *chip, int cmd)
/**
* snd_vx_boot_xilinx - boot up the xilinx interface
+ * @chip: VX core instance
* @boot: the boot record to load
*/
int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
@@ -538,6 +539,8 @@ EXPORT_SYMBOL(snd_vx_threaded_irq_handler);
/**
* snd_vx_irq_handler - interrupt handler
+ * @irq: irq number
+ * @dev: VX core instance
*/
irqreturn_t snd_vx_irq_handler(int irq, void *dev)
{
@@ -649,6 +652,8 @@ static void vx_proc_init(struct vx_core *chip)
/**
* snd_vx_dsp_boot - load the DSP boot
+ * @chip: VX core instance
+ * @boot: firmware data
*/
int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
{
@@ -669,6 +674,8 @@ EXPORT_SYMBOL(snd_vx_dsp_boot);
/**
* snd_vx_dsp_load - load the DSP image
+ * @chip: VX core instance
+ * @dsp: firmware data
*/
int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
{
@@ -768,7 +775,10 @@ EXPORT_SYMBOL(snd_vx_resume);
/**
* snd_vx_create - constructor for struct vx_core
+ * @card: card instance
* @hw: hardware specific record
+ * @ops: VX ops pointer
+ * @extra_size: extra byte size to allocate appending to chip
*
* this function allocates the instance and prepare for the hardware
* initialization.
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 3b6823fc0606..be9477e30739 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -471,30 +471,18 @@ static struct snd_kcontrol_new vx_control_output_level = {
*/
static int vx_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts_mic[3] = {
+ static const char * const texts_mic[3] = {
"Digital", "Line", "Mic"
};
- static char *texts_vx2[2] = {
+ static const char * const texts_vx2[2] = {
"Digital", "Analog"
};
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (chip->type >= VX_TYPE_VXPOCKET) {
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts_mic[uinfo->value.enumerated.item]);
- } else {
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts_vx2[uinfo->value.enumerated.item]);
- }
- return 0;
+ if (chip->type >= VX_TYPE_VXPOCKET)
+ return snd_ctl_enum_info(uinfo, 1, 3, texts_mic);
+ else
+ return snd_ctl_enum_info(uinfo, 1, 2, texts_vx2);
}
static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -539,18 +527,11 @@ static struct snd_kcontrol_new vx_control_audio_src = {
*/
static int vx_clock_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Auto", "Internal", "External"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 46dff64908c8..ecec547782b2 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -13,28 +13,34 @@ config SND_FIREWIRE_LIB
select SND_RAWMIDI
config SND_DICE
- tristate "DICE-based DACs (EXPERIMENTAL)"
+ tristate "DICE-based DACs support"
select SND_HWDEP
select SND_FIREWIRE_LIB
help
Say Y here to include support for many DACs based on the DICE
- chip family (DICE-II/Jr/Mini) from TC Applied Technologies.
-
- At the moment, this driver supports playback only. If you
- want to use devices that support capturing, use FFADO instead.
+ chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces.
To compile this driver as a module, choose M here: the module
will be called snd-dice.
-config SND_FIREWIRE_SPEAKERS
- tristate "FireWire speakers"
+config SND_OXFW
+ tristate "Oxford Semiconductor FW970/971 chipset support"
select SND_FIREWIRE_LIB
+ select SND_HWDEP
help
- Say Y here to include support for the Griffin FireWave Surround
- and the LaCie FireWire Speakers.
+ Say Y here to include support for FireWire devices based on
+ Oxford Semiconductor FW970/971 chipset.
+ * Griffin Firewave
+ * LaCie Firewire Speakers
+ * Behringer F-Control Audio 202
+ * Mackie(Loud) Onyx-i series (former models)
+ * Mackie(Loud) Onyx Satellite
+ * Mackie(Loud) Tapco Link.Firewire
+ * Mackie(Loud) d.2 pro/d.4 pro
+ * Mackie(Loud) U.420/U.420d
To compile this driver as a module, choose M here: the module
- will be called snd-firewire-speakers.
+ will be called snd-oxfw.
config SND_ISIGHT
tristate "Apple iSight microphone"
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index fad8d49306ab..8b37f084b2ab 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,13 +1,12 @@
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp.o
-snd-dice-objs := dice.o
-snd-firewire-speakers-objs := speakers.o
+snd-oxfw-objs := oxfw.o
snd-isight-objs := isight.o
snd-scs1x-objs := scs1x.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
-obj-$(CONFIG_SND_DICE) += snd-dice.o
-obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
+obj-$(CONFIG_SND_DICE) += dice/
+obj-$(CONFIG_SND_OXFW) += oxfw/
obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
obj-$(CONFIG_SND_FIREWORKS) += fireworks/
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 95fc2eaf11dc..3badc70124ab 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -1006,11 +1006,7 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s)
struct snd_pcm_substream *pcm;
pcm = ACCESS_ONCE(s->pcm);
- if (pcm) {
- snd_pcm_stream_lock_irq(pcm);
- if (snd_pcm_running(pcm))
- snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irq(pcm);
- }
+ if (pcm)
+ snd_pcm_stop_xrun(pcm);
}
EXPORT_SYMBOL(amdtp_stream_pcm_abort);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index 4823c08196ac..e6e8926275b0 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -23,7 +23,7 @@
* corresponds to the end of event in the packet. Out of IEC 61883.
* @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets.
* The value of data_block_quadlets is used instead of reported value.
- * @SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
+ * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
* skipped for detecting discontinuity.
* @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first
* packet is not continuous from an initial value.
@@ -43,7 +43,27 @@ enum cip_flags {
};
/**
- * enum cip_sfc - a stream's sample rate
+ * enum cip_sfc - supported Sampling Frequency Codes (SFCs)
+ * @CIP_SFC_32000: 32,000 data blocks
+ * @CIP_SFC_44100: 44,100 data blocks
+ * @CIP_SFC_48000: 48,000 data blocks
+ * @CIP_SFC_88200: 88,200 data blocks
+ * @CIP_SFC_96000: 96,000 data blocks
+ * @CIP_SFC_176400: 176,400 data blocks
+ * @CIP_SFC_192000: 192,000 data blocks
+ * @CIP_SFC_COUNT: the number of supported SFCs
+ *
+ * These values are used to show nominal Sampling Frequency Code in
+ * Format Dependent Field (FDF) of AMDTP packet header. In IEC 61883-6:2002,
+ * this code means the number of events per second. Actually the code
+ * represents the number of data blocks transferred per second in an AMDTP
+ * stream.
+ *
+ * In IEC 61883-6:2005, some extensions were added to support more types of
+ * data such as 'One Bit LInear Audio', therefore the meaning of SFC became
+ * different depending on the types.
+ *
+ * Currently our implementation is compatible with IEC 61883-6:2002.
*/
enum cip_sfc {
CIP_SFC_32000 = 0,
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index e13eef99c27a..dfbcd233178c 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -52,7 +52,7 @@ extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES];
#define SND_BEBOB_CLOCK_INTERNAL "Internal"
struct snd_bebob_clock_spec {
unsigned int num;
- char *const *labels;
+ const char *const *labels;
int (*get)(struct snd_bebob *bebob, unsigned int *id);
};
struct snd_bebob_rate_spec {
@@ -61,7 +61,7 @@ struct snd_bebob_rate_spec {
};
struct snd_bebob_meter_spec {
unsigned int num;
- char *const *labels;
+ const char *const *labels;
int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size);
};
struct snd_bebob_spec {
diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c
index 3b052ed0fbf5..fc67c1b7cb5b 100644
--- a/sound/firewire/bebob/bebob_focusrite.c
+++ b/sound/firewire/bebob/bebob_focusrite.c
@@ -103,10 +103,10 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)
&data, sizeof(__be32), 0);
}
-static char *const saffirepro_10_clk_src_labels[] = {
+static const char *const saffirepro_10_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
};
-static char *const saffirepro_26_clk_src_labels[] = {
+static const char *const saffirepro_26_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock"
};
/* Value maps between registers and labels for SaffirePro 10/26. */
@@ -195,7 +195,7 @@ end:
}
struct snd_bebob_spec saffire_le_spec;
-static char *const saffire_both_clk_src_labels[] = {
+static const char *const saffire_both_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF"
};
static int
@@ -210,12 +210,12 @@ saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
return err;
};
-static char *const saffire_le_meter_labels[] = {
+static const char *const saffire_le_meter_labels[] = {
ANA_IN, ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
STM_IN, STM_IN
};
-static char *const saffire_meter_labels[] = {
+static const char *const saffire_meter_labels[] = {
ANA_IN, ANA_IN,
STM_IN, STM_IN, STM_IN, STM_IN, STM_IN,
};
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c
index 70faa3a32526..a422aaa3bb0c 100644
--- a/sound/firewire/bebob/bebob_maudio.c
+++ b/sound/firewire/bebob/bebob_maudio.c
@@ -340,7 +340,7 @@ end:
}
/* Clock source control for special firmware */
-static char *const special_clk_labels[] = {
+static const char *const special_clk_labels[] = {
SND_BEBOB_CLOCK_INTERNAL " with Digital Mute", "Digital",
"Word Clock", SND_BEBOB_CLOCK_INTERNAL};
static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
@@ -352,17 +352,8 @@ static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
static int special_clk_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_clk_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_clk_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_labels),
+ special_clk_labels);
}
static int special_clk_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -438,23 +429,15 @@ static struct snd_kcontrol_new special_sync_ctl = {
};
/* Digital input interface control for special firmware */
-static char *const special_dig_in_iface_labels[] = {
+static const char *const special_dig_in_iface_labels[] = {
"S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical"
};
static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_dig_in_iface_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_dig_in_iface_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1,
+ ARRAY_SIZE(special_dig_in_iface_labels),
+ special_dig_in_iface_labels);
}
static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -539,23 +522,15 @@ static struct snd_kcontrol_new special_dig_in_iface_ctl = {
};
/* Digital output interface control for special firmware */
-static char *const special_dig_out_iface_labels[] = {
+static const char *const special_dig_out_iface_labels[] = {
"S/PDIF Optical and Coaxial", "ADAT Optical"
};
static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_dig_out_iface_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_dig_out_iface_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1,
+ ARRAY_SIZE(special_dig_out_iface_labels),
+ special_dig_out_iface_labels);
}
static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -631,7 +606,7 @@ end:
}
/* Hardware metering for special firmware */
-static char *const special_meter_labels[] = {
+static const char *const special_meter_labels[] = {
ANA_IN, ANA_IN, ANA_IN, ANA_IN,
SPDIF_IN,
ADAT_IN, ADAT_IN, ADAT_IN, ADAT_IN,
@@ -671,30 +646,30 @@ end:
}
/* last 4 bytes are omitted because it's clock info. */
-static char *const fw410_meter_labels[] = {
+static const char *const fw410_meter_labels[] = {
ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT,
HP_OUT
};
-static char *const audiophile_meter_labels[] = {
+static const char *const audiophile_meter_labels[] = {
ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, DIG_OUT,
HP_OUT, AUX_OUT,
};
-static char *const solo_meter_labels[] = {
+static const char *const solo_meter_labels[] = {
ANA_IN, DIG_IN,
STRM_IN, STRM_IN,
ANA_OUT, DIG_OUT
};
/* no clock info */
-static char *const ozonic_meter_labels[] = {
+static const char *const ozonic_meter_labels[] = {
ANA_IN, ANA_IN,
STRM_IN, STRM_IN,
ANA_OUT, ANA_OUT
};
/* TODO: need testers. these positions are based on authour's assumption */
-static char *const nrv10_meter_labels[] = {
+static const char *const nrv10_meter_labels[] = {
ANA_IN, ANA_IN, ANA_IN, ANA_IN,
DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c
index 9940611f2e1b..ad635004d699 100644
--- a/sound/firewire/bebob/bebob_terratec.c
+++ b/sound/firewire/bebob/bebob_terratec.c
@@ -8,7 +8,7 @@
#include "./bebob.h"
-static char *const phase88_rack_clk_src_labels[] = {
+static const char *const phase88_rack_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "Digital In", "Word Clock"
};
static int
@@ -34,7 +34,7 @@ end:
return err;
}
-static char *const phase24_series_clk_src_labels[] = {
+static const char *const phase24_series_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "Digital In"
};
static int
diff --git a/sound/firewire/bebob/bebob_yamaha.c b/sound/firewire/bebob/bebob_yamaha.c
index 9b7e798180ff..ef1fe3823a9c 100644
--- a/sound/firewire/bebob/bebob_yamaha.c
+++ b/sound/firewire/bebob/bebob_yamaha.c
@@ -28,7 +28,7 @@
* reccomend users to close ffado-mixer at 192.0kHz if mixer is needless.
*/
-static char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"};
+static const char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"};
static int
clk_src_get(struct snd_bebob *bebob, unsigned int *id)
{
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index ba8df5a1be39..ae3bc1940efa 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -114,6 +114,7 @@ static int pcr_modify(struct cmp_connection *c,
* cmp_connection_init - initializes a connection manager
* @c: the connection manager to initialize
* @unit: a unit of the target device
+ * @direction: input or output
* @pcr_index: the index of the iPCR/oPCR on the target device
*/
int cmp_connection_init(struct cmp_connection *c,
@@ -154,6 +155,7 @@ EXPORT_SYMBOL(cmp_connection_init);
/**
* cmp_connection_check_used - check connection is already esablished or not
* @c: the connection manager to be checked
+ * @used: the pointer to store the result of checking the connection
*/
int cmp_connection_check_used(struct cmp_connection *c, bool *used)
{
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
deleted file mode 100644
index e3a04d69c853..000000000000
--- a/sound/firewire/dice.c
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * TC Applied Technologies Digital Interface Communications Engine driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/compat.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/firewire.h>
-#include <sound/hwdep.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include "amdtp.h"
-#include "iso-resources.h"
-#include "lib.h"
-#include "dice-interface.h"
-
-
-struct dice {
- struct snd_card *card;
- struct fw_unit *unit;
- spinlock_t lock;
- struct mutex mutex;
- unsigned int global_offset;
- unsigned int rx_offset;
- unsigned int clock_caps;
- unsigned int rx_channels[3];
- unsigned int rx_midi_ports[3];
- struct fw_address_handler notification_handler;
- int owner_generation;
- int dev_lock_count; /* > 0 driver, < 0 userspace */
- bool dev_lock_changed;
- bool global_enabled;
- struct completion clock_accepted;
- wait_queue_head_t hwdep_wait;
- u32 notification_bits;
- struct fw_iso_resources resources;
- struct amdtp_stream stream;
-};
-
-MODULE_DESCRIPTION("DICE driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static const unsigned int dice_rates[] = {
- /* mode 0 */
- [0] = 32000,
- [1] = 44100,
- [2] = 48000,
- /* mode 1 */
- [3] = 88200,
- [4] = 96000,
- /* mode 2 */
- [5] = 176400,
- [6] = 192000,
-};
-
-static unsigned int rate_to_index(unsigned int rate)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if (dice_rates[i] == rate)
- return i;
-
- return 0;
-}
-
-static unsigned int rate_index_to_mode(unsigned int rate_index)
-{
- return ((int)rate_index - 1) / 2;
-}
-
-static void dice_lock_changed(struct dice *dice)
-{
- dice->dev_lock_changed = true;
- wake_up(&dice->hwdep_wait);
-}
-
-static int dice_try_lock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count < 0) {
- err = -EBUSY;
- goto out;
- }
-
- if (dice->dev_lock_count++ == 0)
- dice_lock_changed(dice);
- err = 0;
-
-out:
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static void dice_unlock(struct dice *dice)
-{
- spin_lock_irq(&dice->lock);
-
- if (WARN_ON(dice->dev_lock_count <= 0))
- goto out;
-
- if (--dice->dev_lock_count == 0)
- dice_lock_changed(dice);
-
-out:
- spin_unlock_irq(&dice->lock);
-}
-
-static inline u64 global_address(struct dice *dice, unsigned int offset)
-{
- return DICE_PRIVATE_SPACE + dice->global_offset + offset;
-}
-
-// TODO: rx index
-static inline u64 rx_address(struct dice *dice, unsigned int offset)
-{
- return DICE_PRIVATE_SPACE + dice->rx_offset + offset;
-}
-
-static int dice_owner_set(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
- int err, errors = 0;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- for (;;) {
- buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
- buffer[1] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
-
- dice->owner_generation = device->generation;
- smp_rmb(); /* node_id vs. generation */
- err = snd_fw_transaction(dice->unit,
- TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8,
- FW_FIXED_GENERATION |
- dice->owner_generation);
-
- if (err == 0) {
- if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
- dev_err(&dice->unit->device,
- "device is already in use\n");
- err = -EBUSY;
- }
- break;
- }
- if (err != -EAGAIN || ++errors >= 3)
- break;
-
- msleep(20);
- }
-
- kfree(buffer);
-
- return err;
-}
-
-static int dice_owner_update(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
- int err;
-
- if (dice->owner_generation == -1)
- return 0;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
- buffer[1] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
-
- dice->owner_generation = device->generation;
- smp_rmb(); /* node_id vs. generation */
- err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8,
- FW_FIXED_GENERATION | dice->owner_generation);
-
- if (err == 0) {
- if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
- dev_err(&dice->unit->device,
- "device is already in use\n");
- err = -EBUSY;
- }
- } else if (err == -EAGAIN) {
- err = 0; /* try again later */
- }
-
- kfree(buffer);
-
- if (err < 0)
- dice->owner_generation = -1;
-
- return err;
-}
-
-static void dice_owner_clear(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return;
-
- buffer[0] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
- buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
- snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8, FW_QUIET |
- FW_FIXED_GENERATION | dice->owner_generation);
-
- kfree(buffer);
-
- dice->owner_generation = -1;
-}
-
-static int dice_enable_set(struct dice *dice)
-{
- __be32 value;
- int err;
-
- value = cpu_to_be32(1);
- err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_ENABLE),
- &value, 4,
- FW_FIXED_GENERATION | dice->owner_generation);
- if (err < 0)
- return err;
-
- dice->global_enabled = true;
-
- return 0;
-}
-
-static void dice_enable_clear(struct dice *dice)
-{
- __be32 value;
-
- if (!dice->global_enabled)
- return;
-
- value = 0;
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_ENABLE),
- &value, 4, FW_QUIET |
- FW_FIXED_GENERATION | dice->owner_generation);
-
- dice->global_enabled = false;
-}
-
-static void dice_notification(struct fw_card *card, struct fw_request *request,
- int tcode, int destination, int source,
- int generation, unsigned long long offset,
- void *data, size_t length, void *callback_data)
-{
- struct dice *dice = callback_data;
- u32 bits;
- unsigned long flags;
-
- if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
- fw_send_response(card, request, RCODE_TYPE_ERROR);
- return;
- }
- if ((offset & 3) != 0) {
- fw_send_response(card, request, RCODE_ADDRESS_ERROR);
- return;
- }
-
- bits = be32_to_cpup(data);
-
- spin_lock_irqsave(&dice->lock, flags);
- dice->notification_bits |= bits;
- spin_unlock_irqrestore(&dice->lock, flags);
-
- fw_send_response(card, request, RCODE_COMPLETE);
-
- if (bits & NOTIFY_CLOCK_ACCEPTED)
- complete(&dice->clock_accepted);
- wake_up(&dice->hwdep_wait);
-}
-
-static int dice_rate_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- struct dice *dice = rule->private;
- const struct snd_interval *channels =
- hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval allowed_rates = {
- .min = UINT_MAX, .max = 0, .integer = 1
- };
- unsigned int i, mode;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) {
- mode = rate_index_to_mode(i);
- if ((dice->clock_caps & (1 << i)) &&
- snd_interval_test(channels, dice->rx_channels[mode])) {
- allowed_rates.min = min(allowed_rates.min,
- dice_rates[i]);
- allowed_rates.max = max(allowed_rates.max,
- dice_rates[i]);
- }
- }
-
- return snd_interval_refine(rate, &allowed_rates);
-}
-
-static int dice_channels_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- struct dice *dice = rule->private;
- const struct snd_interval *rate =
- hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval allowed_channels = {
- .min = UINT_MAX, .max = 0, .integer = 1
- };
- unsigned int i, mode;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if ((dice->clock_caps & (1 << i)) &&
- snd_interval_test(rate, dice_rates[i])) {
- mode = rate_index_to_mode(i);
- allowed_channels.min = min(allowed_channels.min,
- dice->rx_channels[mode]);
- allowed_channels.max = max(allowed_channels.max,
- dice->rx_channels[mode]);
- }
-
- return snd_interval_refine(channels, &allowed_channels);
-}
-
-static int dice_open(struct snd_pcm_substream *substream)
-{
- static const struct snd_pcm_hardware hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = AMDTP_OUT_PCM_FORMAT_BITS,
- .channels_min = UINT_MAX,
- .channels_max = 0,
- .buffer_bytes_max = 16 * 1024 * 1024,
- .period_bytes_min = 1,
- .period_bytes_max = UINT_MAX,
- .periods_min = 1,
- .periods_max = UINT_MAX,
- };
- struct dice *dice = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int i;
- int err;
-
- err = dice_try_lock(dice);
- if (err < 0)
- goto error;
-
- runtime->hw = hardware;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if (dice->clock_caps & (1 << i))
- runtime->hw.rates |=
- snd_pcm_rate_to_rate_bit(dice_rates[i]);
- snd_pcm_limit_hw_rates(runtime);
-
- for (i = 0; i < 3; ++i)
- if (dice->rx_channels[i]) {
- runtime->hw.channels_min = min(runtime->hw.channels_min,
- dice->rx_channels[i]);
- runtime->hw.channels_max = max(runtime->hw.channels_max,
- dice->rx_channels[i]);
- }
-
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- dice_rate_constraint, dice,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- if (err < 0)
- goto err_lock;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dice_channels_constraint, dice,
- SNDRV_PCM_HW_PARAM_RATE, -1);
- if (err < 0)
- goto err_lock;
-
- err = amdtp_stream_add_pcm_hw_constraints(&dice->stream, runtime);
- if (err < 0)
- goto err_lock;
-
- return 0;
-
-err_lock:
- dice_unlock(dice);
-error:
- return err;
-}
-
-static int dice_close(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- dice_unlock(dice);
-
- return 0;
-}
-
-static int dice_stream_start_packets(struct dice *dice)
-{
- int err;
-
- if (amdtp_stream_running(&dice->stream))
- return 0;
-
- err = amdtp_stream_start(&dice->stream, dice->resources.channel,
- fw_parent_device(dice->unit)->max_speed);
- if (err < 0)
- return err;
-
- err = dice_enable_set(dice);
- if (err < 0) {
- amdtp_stream_stop(&dice->stream);
- return err;
- }
-
- return 0;
-}
-
-static int dice_stream_start(struct dice *dice)
-{
- __be32 channel;
- int err;
-
- if (!dice->resources.allocated) {
- err = fw_iso_resources_allocate(&dice->resources,
- amdtp_stream_get_max_payload(&dice->stream),
- fw_parent_device(dice->unit)->max_speed);
- if (err < 0)
- goto error;
-
- channel = cpu_to_be32(dice->resources.channel);
- err = snd_fw_transaction(dice->unit,
- TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS),
- &channel, 4, 0);
- if (err < 0)
- goto err_resources;
- }
-
- err = dice_stream_start_packets(dice);
- if (err < 0)
- goto err_rx_channel;
-
- return 0;
-
-err_rx_channel:
- channel = cpu_to_be32((u32)-1);
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
-err_resources:
- fw_iso_resources_free(&dice->resources);
-error:
- return err;
-}
-
-static void dice_stream_stop_packets(struct dice *dice)
-{
- if (amdtp_stream_running(&dice->stream)) {
- dice_enable_clear(dice);
- amdtp_stream_stop(&dice->stream);
- }
-}
-
-static void dice_stream_stop(struct dice *dice)
-{
- __be32 channel;
-
- dice_stream_stop_packets(dice);
-
- if (!dice->resources.allocated)
- return;
-
- channel = cpu_to_be32((u32)-1);
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
-
- fw_iso_resources_free(&dice->resources);
-}
-
-static int dice_change_rate(struct dice *dice, unsigned int clock_rate)
-{
- __be32 value;
- int err;
-
- reinit_completion(&dice->clock_accepted);
-
- value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1);
- err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &value, 4, 0);
- if (err < 0)
- return err;
-
- if (!wait_for_completion_timeout(&dice->clock_accepted,
- msecs_to_jiffies(100)))
- dev_warn(&dice->unit->device, "clock change timed out\n");
-
- return 0;
-}
-
-static int dice_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct dice *dice = substream->private_data;
- unsigned int rate_index, mode, rate, channels, i;
- int err;
-
- mutex_lock(&dice->mutex);
- dice_stream_stop(dice);
- mutex_unlock(&dice->mutex);
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- rate = params_rate(hw_params);
- rate_index = rate_to_index(rate);
- err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
- if (err < 0)
- return err;
-
- /*
- * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
- * one data block of AMDTP packet. Thus sampling transfer frequency is
- * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
- * transferred on AMDTP packets at 96 kHz. Two successive samples of a
- * channel are stored consecutively in the packet. This quirk is called
- * as 'Dual Wire'.
- * For this quirk, blocking mode is required and PCM buffer size should
- * be aligned to SYT_INTERVAL.
- */
- channels = params_channels(hw_params);
- if (rate_index > 4) {
- if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) {
- err = -ENOSYS;
- return err;
- }
-
- rate /= 2;
- channels *= 2;
- dice->stream.double_pcm_frames = true;
- } else {
- dice->stream.double_pcm_frames = false;
- }
-
- mode = rate_index_to_mode(rate_index);
- amdtp_stream_set_parameters(&dice->stream, rate, channels,
- dice->rx_midi_ports[mode]);
- if (rate_index > 4) {
- channels /= 2;
-
- for (i = 0; i < channels; i++) {
- dice->stream.pcm_positions[i] = i * 2;
- dice->stream.pcm_positions[i + channels] = i * 2 + 1;
- }
- }
-
- amdtp_stream_set_pcm_format(&dice->stream,
- params_format(hw_params));
-
- return 0;
-}
-
-static int dice_hw_free(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- mutex_lock(&dice->mutex);
- dice_stream_stop(dice);
- mutex_unlock(&dice->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int dice_prepare(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
- int err;
-
- mutex_lock(&dice->mutex);
-
- if (amdtp_streaming_error(&dice->stream))
- dice_stream_stop_packets(dice);
-
- err = dice_stream_start(dice);
- if (err < 0) {
- mutex_unlock(&dice->mutex);
- return err;
- }
-
- mutex_unlock(&dice->mutex);
-
- amdtp_stream_pcm_prepare(&dice->stream);
-
- return 0;
-}
-
-static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct dice *dice = substream->private_data;
- struct snd_pcm_substream *pcm;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- pcm = substream;
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pcm = NULL;
- break;
- default:
- return -EINVAL;
- }
- amdtp_stream_pcm_trigger(&dice->stream, pcm);
-
- return 0;
-}
-
-static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- return amdtp_stream_pcm_pointer(&dice->stream);
-}
-
-static int dice_create_pcm(struct dice *dice)
-{
- static struct snd_pcm_ops ops = {
- .open = dice_open,
- .close = dice_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = dice_hw_params,
- .hw_free = dice_hw_free,
- .prepare = dice_prepare,
- .trigger = dice_trigger,
- .pointer = dice_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
- };
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = dice;
- strcpy(pcm->name, dice->card->shortname);
- pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops;
-
- return 0;
-}
-
-static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
- long count, loff_t *offset)
-{
- struct dice *dice = hwdep->private_data;
- DEFINE_WAIT(wait);
- union snd_firewire_event event;
-
- spin_lock_irq(&dice->lock);
-
- while (!dice->dev_lock_changed && dice->notification_bits == 0) {
- prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock_irq(&dice->lock);
- schedule();
- finish_wait(&dice->hwdep_wait, &wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irq(&dice->lock);
- }
-
- memset(&event, 0, sizeof(event));
- if (dice->dev_lock_changed) {
- event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
- event.lock_status.status = dice->dev_lock_count > 0;
- dice->dev_lock_changed = false;
-
- count = min(count, (long)sizeof(event.lock_status));
- } else {
- event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
- event.dice_notification.notification = dice->notification_bits;
- dice->notification_bits = 0;
-
- count = min(count, (long)sizeof(event.dice_notification));
- }
-
- spin_unlock_irq(&dice->lock);
-
- if (copy_to_user(buf, &event, count))
- return -EFAULT;
-
- return count;
-}
-
-static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
- poll_table *wait)
-{
- struct dice *dice = hwdep->private_data;
- unsigned int events;
-
- poll_wait(file, &dice->hwdep_wait, wait);
-
- spin_lock_irq(&dice->lock);
- if (dice->dev_lock_changed || dice->notification_bits != 0)
- events = POLLIN | POLLRDNORM;
- else
- events = 0;
- spin_unlock_irq(&dice->lock);
-
- return events;
-}
-
-static int dice_hwdep_get_info(struct dice *dice, void __user *arg)
-{
- struct fw_device *dev = fw_parent_device(dice->unit);
- struct snd_firewire_get_info info;
-
- memset(&info, 0, sizeof(info));
- info.type = SNDRV_FIREWIRE_TYPE_DICE;
- info.card = dev->card->index;
- *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
- *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
- strlcpy(info.device_name, dev_name(&dev->device),
- sizeof(info.device_name));
-
- if (copy_to_user(arg, &info, sizeof(info)))
- return -EFAULT;
-
- return 0;
-}
-
-static int dice_hwdep_lock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count == 0) {
- dice->dev_lock_count = -1;
- err = 0;
- } else {
- err = -EBUSY;
- }
-
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static int dice_hwdep_unlock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count == -1) {
- dice->dev_lock_count = 0;
- err = 0;
- } else {
- err = -EBADFD;
- }
-
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
-{
- struct dice *dice = hwdep->private_data;
-
- spin_lock_irq(&dice->lock);
- if (dice->dev_lock_count == -1)
- dice->dev_lock_count = 0;
- spin_unlock_irq(&dice->lock);
-
- return 0;
-}
-
-static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct dice *dice = hwdep->private_data;
-
- switch (cmd) {
- case SNDRV_FIREWIRE_IOCTL_GET_INFO:
- return dice_hwdep_get_info(dice, (void __user *)arg);
- case SNDRV_FIREWIRE_IOCTL_LOCK:
- return dice_hwdep_lock(dice);
- case SNDRV_FIREWIRE_IOCTL_UNLOCK:
- return dice_hwdep_unlock(dice);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#ifdef CONFIG_COMPAT
-static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return dice_hwdep_ioctl(hwdep, file, cmd,
- (unsigned long)compat_ptr(arg));
-}
-#else
-#define dice_hwdep_compat_ioctl NULL
-#endif
-
-static int dice_create_hwdep(struct dice *dice)
-{
- static const struct snd_hwdep_ops ops = {
- .read = dice_hwdep_read,
- .release = dice_hwdep_release,
- .poll = dice_hwdep_poll,
- .ioctl = dice_hwdep_ioctl,
- .ioctl_compat = dice_hwdep_compat_ioctl,
- };
- struct snd_hwdep *hwdep;
- int err;
-
- err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
- if (err < 0)
- return err;
- strcpy(hwdep->name, "DICE");
- hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
- hwdep->ops = ops;
- hwdep->private_data = dice;
- hwdep->exclusive = true;
-
- return 0;
-}
-
-static int dice_proc_read_mem(struct dice *dice, void *buffer,
- unsigned int offset_q, unsigned int quadlets)
-{
- unsigned int i;
- int err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE + 4 * offset_q,
- buffer, 4 * quadlets, 0);
- if (err < 0)
- return err;
-
- for (i = 0; i < quadlets; ++i)
- be32_to_cpus(&((u32 *)buffer)[i]);
-
- return 0;
-}
-
-static const char *str_from_array(const char *const strs[], unsigned int count,
- unsigned int i)
-{
- if (i < count)
- return strs[i];
- else
- return "(unknown)";
-}
-
-static void dice_proc_fixup_string(char *s, unsigned int size)
-{
- unsigned int i;
-
- for (i = 0; i < size; i += 4)
- cpu_to_le32s((u32 *)(s + i));
-
- for (i = 0; i < size - 2; ++i) {
- if (s[i] == '\0')
- return;
- if (s[i] == '\\' && s[i + 1] == '\\') {
- s[i + 2] = '\0';
- return;
- }
- }
- s[size - 1] = '\0';
-}
-
-static void dice_proc_read(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- static const char *const section_names[5] = {
- "global", "tx", "rx", "ext_sync", "unused2"
- };
- static const char *const clock_sources[] = {
- "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
- "wc", "arx1", "arx2", "arx3", "arx4", "internal"
- };
- static const char *const rates[] = {
- "32000", "44100", "48000", "88200", "96000", "176400", "192000",
- "any low", "any mid", "any high", "none"
- };
- struct dice *dice = entry->private_data;
- u32 sections[ARRAY_SIZE(section_names) * 2];
- struct {
- u32 number;
- u32 size;
- } tx_rx_header;
- union {
- struct {
- u32 owner_hi, owner_lo;
- u32 notification;
- char nick_name[NICK_NAME_SIZE];
- u32 clock_select;
- u32 enable;
- u32 status;
- u32 extended_status;
- u32 sample_rate;
- u32 version;
- u32 clock_caps;
- char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
- } global;
- struct {
- u32 iso;
- u32 number_audio;
- u32 number_midi;
- u32 speed;
- char names[TX_NAMES_SIZE];
- u32 ac3_caps;
- u32 ac3_enable;
- } tx;
- struct {
- u32 iso;
- u32 seq_start;
- u32 number_audio;
- u32 number_midi;
- char names[RX_NAMES_SIZE];
- u32 ac3_caps;
- u32 ac3_enable;
- } rx;
- struct {
- u32 clock_source;
- u32 locked;
- u32 rate;
- u32 adat_user_data;
- } ext_sync;
- } buf;
- unsigned int quadlets, stream, i;
-
- if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
- return;
- snd_iprintf(buffer, "sections:\n");
- for (i = 0; i < ARRAY_SIZE(section_names); ++i)
- snd_iprintf(buffer, " %s: offset %u, size %u\n",
- section_names[i],
- sections[i * 2], sections[i * 2 + 1]);
-
- quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
- if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
- return;
- snd_iprintf(buffer, "global:\n");
- snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
- buf.global.owner_hi >> 16,
- buf.global.owner_hi & 0xffff, buf.global.owner_lo);
- snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
- dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
- snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
- snd_iprintf(buffer, " clock select: %s %s\n",
- str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
- buf.global.clock_select & CLOCK_SOURCE_MASK),
- str_from_array(rates, ARRAY_SIZE(rates),
- (buf.global.clock_select & CLOCK_RATE_MASK)
- >> CLOCK_RATE_SHIFT));
- snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
- snd_iprintf(buffer, " status: %slocked %s\n",
- buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
- str_from_array(rates, ARRAY_SIZE(rates),
- (buf.global.status &
- STATUS_NOMINAL_RATE_MASK)
- >> CLOCK_RATE_SHIFT));
- snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
- snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
- snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
- (buf.global.version >> 24) & 0xff,
- (buf.global.version >> 16) & 0xff,
- (buf.global.version >> 8) & 0xff,
- (buf.global.version >> 0) & 0xff);
- if (quadlets >= 90) {
- snd_iprintf(buffer, " clock caps:");
- for (i = 0; i <= 6; ++i)
- if (buf.global.clock_caps & (1 << i))
- snd_iprintf(buffer, " %s", rates[i]);
- for (i = 0; i <= 12; ++i)
- if (buf.global.clock_caps & (1 << (16 + i)))
- snd_iprintf(buffer, " %s", clock_sources[i]);
- snd_iprintf(buffer, "\n");
- dice_proc_fixup_string(buf.global.clock_source_names,
- CLOCK_SOURCE_NAMES_SIZE);
- snd_iprintf(buffer, " clock source names: %s\n",
- buf.global.clock_source_names);
- }
-
- if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
- return;
- quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
- for (stream = 0; stream < tx_rx_header.number; ++stream) {
- if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
- stream * tx_rx_header.size,
- quadlets) < 0)
- break;
- snd_iprintf(buffer, "tx %u:\n", stream);
- snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
- snd_iprintf(buffer, " audio channels: %u\n",
- buf.tx.number_audio);
- snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
- snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
- if (quadlets >= 68) {
- dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
- snd_iprintf(buffer, " names: %s\n", buf.tx.names);
- }
- if (quadlets >= 70) {
- snd_iprintf(buffer, " ac3 caps: %08x\n",
- buf.tx.ac3_caps);
- snd_iprintf(buffer, " ac3 enable: %08x\n",
- buf.tx.ac3_enable);
- }
- }
-
- if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
- return;
- quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
- for (stream = 0; stream < tx_rx_header.number; ++stream) {
- if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
- stream * tx_rx_header.size,
- quadlets) < 0)
- break;
- snd_iprintf(buffer, "rx %u:\n", stream);
- snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
- snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
- snd_iprintf(buffer, " audio channels: %u\n",
- buf.rx.number_audio);
- snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
- if (quadlets >= 68) {
- dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
- snd_iprintf(buffer, " names: %s\n", buf.rx.names);
- }
- if (quadlets >= 70) {
- snd_iprintf(buffer, " ac3 caps: %08x\n",
- buf.rx.ac3_caps);
- snd_iprintf(buffer, " ac3 enable: %08x\n",
- buf.rx.ac3_enable);
- }
- }
-
- quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
- if (quadlets >= 4) {
- if (dice_proc_read_mem(dice, &buf.ext_sync,
- sections[6], 4) < 0)
- return;
- snd_iprintf(buffer, "ext status:\n");
- snd_iprintf(buffer, " clock source: %s\n",
- str_from_array(clock_sources,
- ARRAY_SIZE(clock_sources),
- buf.ext_sync.clock_source));
- snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
- snd_iprintf(buffer, " rate: %s\n",
- str_from_array(rates, ARRAY_SIZE(rates),
- buf.ext_sync.rate));
- snd_iprintf(buffer, " adat user data: ");
- if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
- snd_iprintf(buffer, "-\n");
- else
- snd_iprintf(buffer, "%x\n",
- buf.ext_sync.adat_user_data);
- }
-}
-
-static void dice_create_proc(struct dice *dice)
-{
- struct snd_info_entry *entry;
-
- if (!snd_card_proc_new(dice->card, "dice", &entry))
- snd_info_set_text_ops(entry, dice, dice_proc_read);
-}
-
-static void dice_card_free(struct snd_card *card)
-{
- struct dice *dice = card->private_data;
-
- amdtp_stream_destroy(&dice->stream);
- fw_core_remove_address_handler(&dice->notification_handler);
- mutex_destroy(&dice->mutex);
-}
-
-#define OUI_WEISS 0x001c6a
-
-#define DICE_CATEGORY_ID 0x04
-#define WEISS_CATEGORY_ID 0x00
-
-static int dice_interface_check(struct fw_unit *unit)
-{
- static const int min_values[10] = {
- 10, 0x64 / 4,
- 10, 0x18 / 4,
- 10, 0x18 / 4,
- 0, 0,
- 0, 0,
- };
- struct fw_device *device = fw_parent_device(unit);
- struct fw_csr_iterator it;
- int key, value, vendor = -1, model = -1, err;
- unsigned int category, i;
- __be32 pointers[ARRAY_SIZE(min_values)];
- __be32 tx_data[4];
- __be32 version;
-
- /*
- * Check that GUID and unit directory are constructed according to DICE
- * rules, i.e., that the specifier ID is the GUID's OUI, and that the
- * GUID chip ID consists of the 8-bit category ID, the 10-bit product
- * ID, and a 22-bit serial number.
- */
- fw_csr_iterator_init(&it, unit->directory);
- while (fw_csr_iterator_next(&it, &key, &value)) {
- switch (key) {
- case CSR_SPECIFIER_ID:
- vendor = value;
- break;
- case CSR_MODEL:
- model = value;
- break;
- }
- }
- if (vendor == OUI_WEISS)
- category = WEISS_CATEGORY_ID;
- else
- category = DICE_CATEGORY_ID;
- if (device->config_rom[3] != ((vendor << 8) | category) ||
- device->config_rom[4] >> 22 != model)
- return -ENODEV;
-
- /*
- * Check that the sub address spaces exist and are located inside the
- * private address space. The minimum values are chosen so that all
- * minimally required registers are included.
- */
- err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE,
- pointers, sizeof(pointers), 0);
- if (err < 0)
- return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(pointers); ++i) {
- value = be32_to_cpu(pointers[i]);
- if (value < min_values[i] || value >= 0x40000)
- return -ENODEV;
- }
-
- /* We support playback only. Let capture devices be handled by FFADO. */
- err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE +
- be32_to_cpu(pointers[2]) * 4,
- tx_data, sizeof(tx_data), 0);
- if (err < 0 || (tx_data[0] && tx_data[3]))
- return -ENODEV;
-
- /*
- * Check that the implemented DICE driver specification major version
- * number matches.
- */
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- DICE_PRIVATE_SPACE +
- be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
- &version, 4, 0);
- if (err < 0)
- return -ENODEV;
- if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
- dev_err(&unit->device,
- "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int highest_supported_mode_rate(struct dice *dice, unsigned int mode)
-{
- int i;
-
- for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i)
- if ((dice->clock_caps & (1 << i)) &&
- rate_index_to_mode(i) == mode)
- return i;
-
- return -1;
-}
-
-static int dice_read_mode_params(struct dice *dice, unsigned int mode)
-{
- __be32 values[2];
- int rate_index, err;
-
- rate_index = highest_supported_mode_rate(dice, mode);
- if (rate_index < 0) {
- dice->rx_channels[mode] = 0;
- dice->rx_midi_ports[mode] = 0;
- return 0;
- }
-
- err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
- if (err < 0)
- return err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- rx_address(dice, RX_NUMBER_AUDIO),
- values, 2 * 4, 0);
- if (err < 0)
- return err;
-
- dice->rx_channels[mode] = be32_to_cpu(values[0]);
- dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
-
- return 0;
-}
-
-static int dice_read_params(struct dice *dice)
-{
- __be32 pointers[6];
- __be32 value;
- int mode, err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE,
- pointers, sizeof(pointers), 0);
- if (err < 0)
- return err;
-
- dice->global_offset = be32_to_cpu(pointers[0]) * 4;
- dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
-
- /* some very old firmwares don't tell about their clock support */
- if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) {
- err = snd_fw_transaction(
- dice->unit, TCODE_READ_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_CAPABILITIES),
- &value, 4, 0);
- if (err < 0)
- return err;
- dice->clock_caps = be32_to_cpu(value);
- } else {
- /* this should be supported by any device */
- dice->clock_caps = CLOCK_CAP_RATE_44100 |
- CLOCK_CAP_RATE_48000 |
- CLOCK_CAP_SOURCE_ARX1 |
- CLOCK_CAP_SOURCE_INTERNAL;
- }
-
- for (mode = 2; mode >= 0; --mode) {
- err = dice_read_mode_params(dice, mode);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static void dice_card_strings(struct dice *dice)
-{
- struct snd_card *card = dice->card;
- struct fw_device *dev = fw_parent_device(dice->unit);
- char vendor[32], model[32];
- unsigned int i;
- int err;
-
- strcpy(card->driver, "DICE");
-
- strcpy(card->shortname, "DICE");
- BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- global_address(dice, GLOBAL_NICK_NAME),
- card->shortname, sizeof(card->shortname), 0);
- if (err >= 0) {
- /* DICE strings are returned in "always-wrong" endianness */
- BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
- for (i = 0; i < sizeof(card->shortname); i += 4)
- swab32s((u32 *)&card->shortname[i]);
- card->shortname[sizeof(card->shortname) - 1] = '\0';
- }
-
- strcpy(vendor, "?");
- fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
- strcpy(model, "?");
- fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
- snprintf(card->longname, sizeof(card->longname),
- "%s %s (serial %u) at %s, S%d",
- vendor, model, dev->config_rom[4] & 0x3fffff,
- dev_name(&dice->unit->device), 100 << dev->max_speed);
-
- strcpy(card->mixername, "DICE");
-}
-
-static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
-{
- struct snd_card *card;
- struct dice *dice;
- __be32 clock_sel;
- int err;
-
- err = dice_interface_check(unit);
- if (err < 0)
- return err;
-
- err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
- sizeof(*dice), &card);
- if (err < 0)
- return err;
-
- dice = card->private_data;
- dice->card = card;
- spin_lock_init(&dice->lock);
- mutex_init(&dice->mutex);
- dice->unit = unit;
- init_completion(&dice->clock_accepted);
- init_waitqueue_head(&dice->hwdep_wait);
-
- dice->notification_handler.length = 4;
- dice->notification_handler.address_callback = dice_notification;
- dice->notification_handler.callback_data = dice;
- err = fw_core_add_address_handler(&dice->notification_handler,
- &fw_high_memory_region);
- if (err < 0)
- goto err_mutex;
-
- err = dice_owner_set(dice);
- if (err < 0)
- goto err_notification_handler;
-
- err = dice_read_params(dice);
- if (err < 0)
- goto err_owner;
-
- err = fw_iso_resources_init(&dice->resources, unit);
- if (err < 0)
- goto err_owner;
- dice->resources.channels_mask = 0x00000000ffffffffuLL;
-
- err = amdtp_stream_init(&dice->stream, unit, AMDTP_OUT_STREAM,
- CIP_BLOCKING);
- if (err < 0)
- goto err_resources;
-
- card->private_free = dice_card_free;
-
- dice_card_strings(dice);
-
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &clock_sel, 4, 0);
- if (err < 0)
- goto error;
- clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
- clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
- err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &clock_sel, 4, 0);
- if (err < 0)
- goto error;
-
- err = dice_create_pcm(dice);
- if (err < 0)
- goto error;
-
- err = dice_create_hwdep(dice);
- if (err < 0)
- goto error;
-
- dice_create_proc(dice);
-
- err = snd_card_register(card);
- if (err < 0)
- goto error;
-
- dev_set_drvdata(&unit->device, dice);
-
- return 0;
-
-err_resources:
- fw_iso_resources_destroy(&dice->resources);
-err_owner:
- dice_owner_clear(dice);
-err_notification_handler:
- fw_core_remove_address_handler(&dice->notification_handler);
-err_mutex:
- mutex_destroy(&dice->mutex);
-error:
- snd_card_free(card);
- return err;
-}
-
-static void dice_remove(struct fw_unit *unit)
-{
- struct dice *dice = dev_get_drvdata(&unit->device);
-
- amdtp_stream_pcm_abort(&dice->stream);
-
- snd_card_disconnect(dice->card);
-
- mutex_lock(&dice->mutex);
-
- dice_stream_stop(dice);
- dice_owner_clear(dice);
-
- mutex_unlock(&dice->mutex);
-
- snd_card_free_when_closed(dice->card);
-}
-
-static void dice_bus_reset(struct fw_unit *unit)
-{
- struct dice *dice = dev_get_drvdata(&unit->device);
-
- /*
- * On a bus reset, the DICE firmware disables streaming and then goes
- * off contemplating its own navel for hundreds of milliseconds before
- * it can react to any of our attempts to reenable streaming. This
- * means that we lose synchronization anyway, so we force our streams
- * to stop so that the application can restart them in an orderly
- * manner.
- */
- amdtp_stream_pcm_abort(&dice->stream);
-
- mutex_lock(&dice->mutex);
-
- dice->global_enabled = false;
- dice_stream_stop_packets(dice);
-
- dice_owner_update(dice);
-
- fw_iso_resources_update(&dice->resources);
-
- mutex_unlock(&dice->mutex);
-}
-
-#define DICE_INTERFACE 0x000001
-
-static const struct ieee1394_device_id dice_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_VERSION,
- .version = DICE_INTERFACE,
- },
- { }
-};
-MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
-
-static struct fw_driver dice_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = KBUILD_MODNAME,
- .bus = &fw_bus_type,
- },
- .probe = dice_probe,
- .update = dice_bus_reset,
- .remove = dice_remove,
- .id_table = dice_id_table,
-};
-
-static int __init alsa_dice_init(void)
-{
- return driver_register(&dice_driver.driver);
-}
-
-static void __exit alsa_dice_exit(void)
-{
- driver_unregister(&dice_driver.driver);
-}
-
-module_init(alsa_dice_init);
-module_exit(alsa_dice_exit);
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
new file mode 100644
index 000000000000..9ef228ef7baf
--- /dev/null
+++ b/sound/firewire/dice/Makefile
@@ -0,0 +1,3 @@
+snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
+ dice-pcm.o dice-hwdep.o dice.o
+obj-m += snd-dice.o
diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c
new file mode 100644
index 000000000000..a4dc02a86f12
--- /dev/null
+++ b/sound/firewire/dice/dice-hwdep.c
@@ -0,0 +1,190 @@
+/*
+ * dice_hwdep.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct snd_dice *dice = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&dice->lock);
+
+ while (!dice->dev_lock_changed && dice->notification_bits == 0) {
+ prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&dice->lock);
+ schedule();
+ finish_wait(&dice->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&dice->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (dice->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = dice->dev_lock_count > 0;
+ dice->dev_lock_changed = false;
+
+ count = min_t(long, count, sizeof(event.lock_status));
+ } else {
+ event.dice_notification.type =
+ SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
+ event.dice_notification.notification = dice->notification_bits;
+ dice->notification_bits = 0;
+
+ count = min_t(long, count, sizeof(event.dice_notification));
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct snd_dice *dice = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &dice->hwdep_wait, wait);
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_changed || dice->notification_bits != 0)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return events;
+}
+
+static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_DICE;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int hwdep_lock(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == 0) {
+ dice->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int hwdep_unlock(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == -1) {
+ dice->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct snd_dice *dice = hwdep->private_data;
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_count == -1)
+ dice->dev_lock_count = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct snd_dice *dice = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return hwdep_get_info(dice, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return hwdep_lock(dice);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return hwdep_unlock(dice);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+int snd_dice_create_hwdep(struct snd_dice *dice)
+{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
+ struct snd_hwdep *hwdep;
+ int err;
+
+ err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
+ if (err < 0)
+ return err;
+ strcpy(hwdep->name, "DICE");
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
+ hwdep->ops = ops;
+ hwdep->private_data = dice;
+ hwdep->exclusive = true;
+
+ return 0;
+}
diff --git a/sound/firewire/dice-interface.h b/sound/firewire/dice/dice-interface.h
index 27b044f84c81..27b044f84c81 100644
--- a/sound/firewire/dice-interface.h
+++ b/sound/firewire/dice/dice-interface.h
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
new file mode 100644
index 000000000000..fe43ce791f84
--- /dev/null
+++ b/sound/firewire/dice/dice-midi.c
@@ -0,0 +1,157 @@
+/*
+ * dice_midi.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+#include "dice.h"
+
+static int midi_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_dice *dice = substream->rmidi->private_data;
+ int err;
+
+ err = snd_dice_stream_lock_try(dice);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&dice->mutex);
+
+ dice->substreams_counter++;
+ err = snd_dice_stream_start_duplex(dice, 0);
+
+ mutex_unlock(&dice->mutex);
+
+ if (err < 0)
+ snd_dice_stream_lock_release(dice);
+
+ return err;
+}
+
+static int midi_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_dice *dice = substream->rmidi->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ dice->substreams_counter--;
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ snd_dice_stream_lock_release(dice);
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_dice *dice = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dice->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&dice->tx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&dice->tx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&dice->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_dice *dice = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dice->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&dice->rx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&dice->rx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&dice->lock, flags);
+}
+
+static struct snd_rawmidi_ops capture_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops playback_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_dice *dice,
+ struct snd_rawmidi_str *str)
+{
+ struct snd_rawmidi_substream *subs;
+
+ list_for_each_entry(subs, &str->substreams, list) {
+ snprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", dice->card->shortname, subs->number + 1);
+ }
+}
+
+int snd_dice_create_midi(struct snd_dice *dice)
+{
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *str;
+ unsigned int i, midi_in_ports, midi_out_ports;
+ int err;
+
+ midi_in_ports = midi_out_ports = 0;
+ for (i = 0; i < 3; i++) {
+ midi_in_ports = max(dice->tx_midi_ports[i], midi_in_ports);
+ midi_out_ports = max(dice->rx_midi_ports[i], midi_out_ports);
+ }
+
+ if (midi_in_ports + midi_out_ports == 0)
+ return 0;
+
+ /* create midi ports */
+ err = snd_rawmidi_new(dice->card, dice->card->driver, 0,
+ midi_out_ports, midi_in_ports,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", dice->card->shortname);
+ rmidi->private_data = dice;
+
+ if (midi_in_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &capture_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+
+ set_midi_substream_names(dice, str);
+ }
+
+ if (midi_out_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &playback_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+
+ set_midi_substream_names(dice, str);
+ }
+
+ if ((midi_out_ports > 0) && (midi_in_ports > 0))
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
new file mode 100644
index 000000000000..f77714511f8b
--- /dev/null
+++ b/sound/firewire/dice/dice-pcm.c
@@ -0,0 +1,422 @@
+/*
+ * dice_pcm.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static int dice_rate_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_substream *substream = rule->private;
+ struct snd_dice *dice = substream->private_data;
+
+ const struct snd_interval *c =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval rates = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, rate, mode, *pcm_channels;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm_channels = dice->tx_channels;
+ else
+ pcm_channels = dice->rx_channels;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+
+ if (!snd_interval_test(c, pcm_channels[mode]))
+ continue;
+
+ rates.min = min(rates.min, rate);
+ rates.max = max(rates.max, rate);
+ }
+
+ return snd_interval_refine(r, &rates);
+}
+
+static int dice_channels_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_substream *substream = rule->private;
+ struct snd_dice *dice = substream->private_data;
+
+ const struct snd_interval *r =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval channels = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, rate, mode, *pcm_channels;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm_channels = dice->tx_channels;
+ else
+ pcm_channels = dice->rx_channels;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+
+ if (!snd_interval_test(r, rate))
+ continue;
+
+ channels.min = min(channels.min, pcm_channels[mode]);
+ channels.max = max(channels.max, pcm_channels[mode]);
+ }
+
+ return snd_interval_refine(c, &channels);
+}
+
+static void limit_channels_and_rates(struct snd_dice *dice,
+ struct snd_pcm_runtime *runtime,
+ unsigned int *pcm_channels)
+{
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ unsigned int i, rate, mode;
+
+ hw->channels_min = UINT_MAX;
+ hw->channels_max = 0;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+ hw->rates |= snd_pcm_rate_to_rate_bit(rate);
+
+ if (pcm_channels[mode] == 0)
+ continue;
+ hw->channels_min = min(hw->channels_min, pcm_channels[mode]);
+ hw->channels_max = max(hw->channels_max, pcm_channels[mode]);
+ }
+
+ snd_pcm_limit_hw_rates(runtime);
+}
+
+static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
+{
+ hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
+ hw->periods_max = UINT_MAX;
+
+ hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */
+
+ /* Just to prevent from allocating much pages. */
+ hw->period_bytes_max = hw->period_bytes_min * 2048;
+ hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
+}
+
+static int init_hw_info(struct snd_dice *dice,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ struct amdtp_stream *stream;
+ unsigned int *pcm_channels;
+ int err;
+
+ hw->info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ hw->formats = AMDTP_IN_PCM_FORMAT_BITS;
+ stream = &dice->tx_stream;
+ pcm_channels = dice->tx_channels;
+ } else {
+ hw->formats = AMDTP_OUT_PCM_FORMAT_BITS;
+ stream = &dice->rx_stream;
+ pcm_channels = dice->rx_channels;
+ }
+
+ limit_channels_and_rates(dice, runtime, pcm_channels);
+ limit_period_and_buffer(hw);
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ dice_rate_constraint, substream,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto end;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ dice_channels_constraint, substream,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+end:
+ return err;
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ unsigned int source, rate;
+ bool internal;
+ int err;
+
+ err = snd_dice_stream_lock_try(dice);
+ if (err < 0)
+ goto end;
+
+ err = init_hw_info(dice, substream);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_dice_transaction_get_clock_source(dice, &source);
+ if (err < 0)
+ goto err_locked;
+ switch (source) {
+ case CLOCK_SOURCE_AES1:
+ case CLOCK_SOURCE_AES2:
+ case CLOCK_SOURCE_AES3:
+ case CLOCK_SOURCE_AES4:
+ case CLOCK_SOURCE_AES_ANY:
+ case CLOCK_SOURCE_ADAT:
+ case CLOCK_SOURCE_TDIF:
+ case CLOCK_SOURCE_WC:
+ internal = false;
+ break;
+ default:
+ internal = true;
+ break;
+ }
+
+ /*
+ * When source of clock is not internal or any PCM streams are running,
+ * available sampling rate is limited at current sampling rate.
+ */
+ if (!internal ||
+ amdtp_stream_pcm_running(&dice->tx_stream) ||
+ amdtp_stream_pcm_running(&dice->rx_stream)) {
+ err = snd_dice_transaction_get_rate(dice, &rate);
+ if (err < 0)
+ goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+ }
+
+ snd_pcm_set_sync(substream);
+end:
+ return err;
+err_locked:
+ snd_dice_stream_lock_release(dice);
+ return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ snd_dice_stream_lock_release(dice);
+
+ return 0;
+}
+
+static int capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&dice->mutex);
+ dice->substreams_counter++;
+ mutex_unlock(&dice->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&dice->tx_stream,
+ params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+static int playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&dice->mutex);
+ dice->substreams_counter++;
+ mutex_unlock(&dice->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&dice->rx_stream,
+ params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ dice->substreams_counter--;
+
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ dice->substreams_counter--;
+
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ int err;
+
+ mutex_lock(&dice->mutex);
+ err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ mutex_unlock(&dice->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&dice->tx_stream);
+
+ return 0;
+}
+static int playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ int err;
+
+ mutex_lock(&dice->mutex);
+ err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ mutex_unlock(&dice->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&dice->rx_stream);
+
+ return err;
+}
+
+static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&dice->tx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&dice->tx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&dice->rx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&dice->rx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&dice->tx_stream);
+}
+static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&dice->rx_stream);
+}
+
+int snd_dice_create_pcm(struct snd_dice *dice)
+{
+ static struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = capture_hw_params,
+ .hw_free = capture_hw_free,
+ .prepare = capture_prepare,
+ .trigger = capture_trigger,
+ .pointer = capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ static struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = playback_hw_params,
+ .hw_free = playback_hw_free,
+ .prepare = playback_prepare,
+ .trigger = playback_trigger,
+ .pointer = playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ unsigned int i, capture, playback;
+ int err;
+
+ capture = playback = 0;
+ for (i = 0; i < 3; i++) {
+ if (dice->tx_channels[i] > 0)
+ capture = 1;
+ if (dice->rx_channels[i] > 0)
+ playback = 1;
+ }
+
+ err = snd_pcm_new(dice->card, "DICE", 0, playback, capture, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = dice;
+ strcpy(pcm->name, dice->card->shortname);
+
+ if (capture > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
+
+ if (playback > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c
new file mode 100644
index 000000000000..f5c1d1bced59
--- /dev/null
+++ b/sound/firewire/dice/dice-proc.c
@@ -0,0 +1,252 @@
+/*
+ * dice_proc.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,
+ unsigned int offset_q, unsigned int quadlets)
+{
+ unsigned int i;
+ int err;
+
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE + 4 * offset_q,
+ buffer, 4 * quadlets, 0);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < quadlets; ++i)
+ be32_to_cpus(&((u32 *)buffer)[i]);
+
+ return 0;
+}
+
+static const char *str_from_array(const char *const strs[], unsigned int count,
+ unsigned int i)
+{
+ if (i < count)
+ return strs[i];
+
+ return "(unknown)";
+}
+
+static void dice_proc_fixup_string(char *s, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i += 4)
+ cpu_to_le32s((u32 *)(s + i));
+
+ for (i = 0; i < size - 2; ++i) {
+ if (s[i] == '\0')
+ return;
+ if (s[i] == '\\' && s[i + 1] == '\\') {
+ s[i + 2] = '\0';
+ return;
+ }
+ }
+ s[size - 1] = '\0';
+}
+
+static void dice_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ static const char *const section_names[5] = {
+ "global", "tx", "rx", "ext_sync", "unused2"
+ };
+ static const char *const clock_sources[] = {
+ "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
+ "wc", "arx1", "arx2", "arx3", "arx4", "internal"
+ };
+ static const char *const rates[] = {
+ "32000", "44100", "48000", "88200", "96000", "176400", "192000",
+ "any low", "any mid", "any high", "none"
+ };
+ struct snd_dice *dice = entry->private_data;
+ u32 sections[ARRAY_SIZE(section_names) * 2];
+ struct {
+ u32 number;
+ u32 size;
+ } tx_rx_header;
+ union {
+ struct {
+ u32 owner_hi, owner_lo;
+ u32 notification;
+ char nick_name[NICK_NAME_SIZE];
+ u32 clock_select;
+ u32 enable;
+ u32 status;
+ u32 extended_status;
+ u32 sample_rate;
+ u32 version;
+ u32 clock_caps;
+ char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
+ } global;
+ struct {
+ u32 iso;
+ u32 number_audio;
+ u32 number_midi;
+ u32 speed;
+ char names[TX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } tx;
+ struct {
+ u32 iso;
+ u32 seq_start;
+ u32 number_audio;
+ u32 number_midi;
+ char names[RX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } rx;
+ struct {
+ u32 clock_source;
+ u32 locked;
+ u32 rate;
+ u32 adat_user_data;
+ } ext_sync;
+ } buf;
+ unsigned int quadlets, stream, i;
+
+ if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
+ return;
+ snd_iprintf(buffer, "sections:\n");
+ for (i = 0; i < ARRAY_SIZE(section_names); ++i)
+ snd_iprintf(buffer, " %s: offset %u, size %u\n",
+ section_names[i],
+ sections[i * 2], sections[i * 2 + 1]);
+
+ quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
+ if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
+ return;
+ snd_iprintf(buffer, "global:\n");
+ snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
+ buf.global.owner_hi >> 16,
+ buf.global.owner_hi & 0xffff, buf.global.owner_lo);
+ snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
+ dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
+ snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
+ snd_iprintf(buffer, " clock select: %s %s\n",
+ str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
+ buf.global.clock_select & CLOCK_SOURCE_MASK),
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.clock_select & CLOCK_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
+ snd_iprintf(buffer, " status: %slocked %s\n",
+ buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.status &
+ STATUS_NOMINAL_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
+ snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
+ snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
+ (buf.global.version >> 24) & 0xff,
+ (buf.global.version >> 16) & 0xff,
+ (buf.global.version >> 8) & 0xff,
+ (buf.global.version >> 0) & 0xff);
+ if (quadlets >= 90) {
+ snd_iprintf(buffer, " clock caps:");
+ for (i = 0; i <= 6; ++i)
+ if (buf.global.clock_caps & (1 << i))
+ snd_iprintf(buffer, " %s", rates[i]);
+ for (i = 0; i <= 12; ++i)
+ if (buf.global.clock_caps & (1 << (16 + i)))
+ snd_iprintf(buffer, " %s", clock_sources[i]);
+ snd_iprintf(buffer, "\n");
+ dice_proc_fixup_string(buf.global.clock_source_names,
+ CLOCK_SOURCE_NAMES_SIZE);
+ snd_iprintf(buffer, " clock source names: %s\n",
+ buf.global.clock_source_names);
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "tx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.tx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
+ snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.tx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.tx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.tx.ac3_enable);
+ }
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "rx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
+ snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.rx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.rx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.rx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.rx.ac3_enable);
+ }
+ }
+
+ quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
+ if (quadlets >= 4) {
+ if (dice_proc_read_mem(dice, &buf.ext_sync,
+ sections[6], 4) < 0)
+ return;
+ snd_iprintf(buffer, "ext status:\n");
+ snd_iprintf(buffer, " clock source: %s\n",
+ str_from_array(clock_sources,
+ ARRAY_SIZE(clock_sources),
+ buf.ext_sync.clock_source));
+ snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
+ snd_iprintf(buffer, " rate: %s\n",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ buf.ext_sync.rate));
+ snd_iprintf(buffer, " adat user data: ");
+ if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
+ snd_iprintf(buffer, "-\n");
+ else
+ snd_iprintf(buffer, "%x\n",
+ buf.ext_sync.adat_user_data);
+ }
+}
+
+void snd_dice_create_proc(struct snd_dice *dice)
+{
+ struct snd_info_entry *entry;
+
+ if (!snd_card_proc_new(dice->card, "dice", &entry))
+ snd_info_set_text_ops(entry, dice, dice_proc_read);
+}
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
new file mode 100644
index 000000000000..fa9cf761b610
--- /dev/null
+++ b/sound/firewire/dice/dice-stream.c
@@ -0,0 +1,407 @@
+/*
+ * dice_stream.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+#define CALLBACK_TIMEOUT 200
+
+const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
+ /* mode 0 */
+ [0] = 32000,
+ [1] = 44100,
+ [2] = 48000,
+ /* mode 1 */
+ [3] = 88200,
+ [4] = 96000,
+ /* mode 2 */
+ [5] = 176400,
+ [6] = 192000,
+};
+
+int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
+ unsigned int *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
+ if (!(dice->clock_caps & BIT(i)))
+ continue;
+ if (snd_dice_rates[i] != rate)
+ continue;
+
+ *mode = (i - 1) / 2;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void release_resources(struct snd_dice *dice,
+ struct fw_iso_resources *resources)
+{
+ unsigned int channel;
+
+ /* Reset channel number */
+ channel = cpu_to_be32((u32)-1);
+ if (resources == &dice->tx_resources)
+ snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
+ &channel, 4);
+ else
+ snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
+ &channel, 4);
+
+ fw_iso_resources_free(resources);
+}
+
+static int keep_resources(struct snd_dice *dice,
+ struct fw_iso_resources *resources,
+ unsigned int max_payload_bytes)
+{
+ unsigned int channel;
+ int err;
+
+ err = fw_iso_resources_allocate(resources, max_payload_bytes,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ goto end;
+
+ /* Set channel number */
+ channel = cpu_to_be32(resources->channel);
+ if (resources == &dice->tx_resources)
+ err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
+ &channel, 4);
+ else
+ err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
+ &channel, 4);
+ if (err < 0)
+ release_resources(dice, resources);
+end:
+ return err;
+}
+
+static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ amdtp_stream_pcm_abort(stream);
+ amdtp_stream_stop(stream);
+
+ if (stream == &dice->tx_stream)
+ release_resources(dice, &dice->tx_resources);
+ else
+ release_resources(dice, &dice->rx_resources);
+}
+
+static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
+ unsigned int rate)
+{
+ struct fw_iso_resources *resources;
+ unsigned int i, mode, pcm_chs, midi_ports;
+ int err;
+
+ err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
+ if (err < 0)
+ goto end;
+ if (stream == &dice->tx_stream) {
+ resources = &dice->tx_resources;
+ pcm_chs = dice->tx_channels[mode];
+ midi_ports = dice->tx_midi_ports[mode];
+ } else {
+ resources = &dice->rx_resources;
+ pcm_chs = dice->rx_channels[mode];
+ midi_ports = dice->rx_midi_ports[mode];
+ }
+
+ /*
+ * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
+ * one data block of AMDTP packet. Thus sampling transfer frequency is
+ * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
+ * transferred on AMDTP packets at 96 kHz. Two successive samples of a
+ * channel are stored consecutively in the packet. This quirk is called
+ * as 'Dual Wire'.
+ * For this quirk, blocking mode is required and PCM buffer size should
+ * be aligned to SYT_INTERVAL.
+ */
+ if (mode > 1) {
+ rate /= 2;
+ pcm_chs *= 2;
+ stream->double_pcm_frames = true;
+ } else {
+ stream->double_pcm_frames = false;
+ }
+
+ amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
+ if (mode > 1) {
+ pcm_chs /= 2;
+
+ for (i = 0; i < pcm_chs; i++) {
+ stream->pcm_positions[i] = i * 2;
+ stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
+ }
+ }
+
+ err = keep_resources(dice, resources,
+ amdtp_stream_get_max_payload(stream));
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to keep isochronous resources\n");
+ goto end;
+ }
+
+ err = amdtp_stream_start(stream, resources->channel,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ release_resources(dice, resources);
+end:
+ return err;
+}
+
+static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode)
+{
+ u32 source;
+ int err;
+
+ err = snd_dice_transaction_get_clock_source(dice, &source);
+ if (err < 0)
+ goto end;
+
+ switch (source) {
+ /* So-called 'SYT Match' modes, sync_to_syt value of packets received */
+ case CLOCK_SOURCE_ARX4: /* in 4th stream */
+ case CLOCK_SOURCE_ARX3: /* in 3rd stream */
+ case CLOCK_SOURCE_ARX2: /* in 2nd stream */
+ err = -ENOSYS;
+ break;
+ case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */
+ *sync_mode = 0;
+ break;
+ default:
+ *sync_mode = CIP_SYNC_TO_DEVICE;
+ break;
+ }
+end:
+ return err;
+}
+
+int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
+{
+ struct amdtp_stream *master, *slave;
+ unsigned int curr_rate;
+ enum cip_flags sync_mode;
+ int err = 0;
+
+ if (dice->substreams_counter == 0)
+ goto end;
+
+ err = get_sync_mode(dice, &sync_mode);
+ if (err < 0)
+ goto end;
+ if (sync_mode == CIP_SYNC_TO_DEVICE) {
+ master = &dice->tx_stream;
+ slave = &dice->rx_stream;
+ } else {
+ master = &dice->rx_stream;
+ slave = &dice->tx_stream;
+ }
+
+ /* Some packet queueing errors. */
+ if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
+ stop_stream(dice, master);
+
+ /* Stop stream if rate is different. */
+ err = snd_dice_transaction_get_rate(dice, &curr_rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to get sampling rate\n");
+ goto end;
+ }
+ if (rate == 0)
+ rate = curr_rate;
+ if (rate != curr_rate)
+ stop_stream(dice, master);
+
+ if (!amdtp_stream_running(master)) {
+ stop_stream(dice, slave);
+ snd_dice_transaction_clear_enable(dice);
+
+ amdtp_stream_set_sync(sync_mode, master, slave);
+
+ err = snd_dice_transaction_set_rate(dice, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to set sampling rate\n");
+ goto end;
+ }
+
+ /* Start both streams. */
+ err = start_stream(dice, master, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to start AMDTP master stream\n");
+ goto end;
+ }
+ err = start_stream(dice, slave, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to start AMDTP slave stream\n");
+ stop_stream(dice, master);
+ goto end;
+ }
+ err = snd_dice_transaction_set_enable(dice);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to enable interface\n");
+ stop_stream(dice, master);
+ stop_stream(dice, slave);
+ goto end;
+ }
+
+ /* Wait first callbacks */
+ if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) ||
+ !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
+ snd_dice_transaction_clear_enable(dice);
+ stop_stream(dice, master);
+ stop_stream(dice, slave);
+ err = -ETIMEDOUT;
+ }
+ }
+end:
+ return err;
+}
+
+void snd_dice_stream_stop_duplex(struct snd_dice *dice)
+{
+ if (dice->substreams_counter > 0)
+ return;
+
+ snd_dice_transaction_clear_enable(dice);
+
+ stop_stream(dice, &dice->tx_stream);
+ stop_stream(dice, &dice->rx_stream);
+}
+
+static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ int err;
+ struct fw_iso_resources *resources;
+ enum amdtp_stream_direction dir;
+
+ if (stream == &dice->tx_stream) {
+ resources = &dice->tx_resources;
+ dir = AMDTP_IN_STREAM;
+ } else {
+ resources = &dice->rx_resources;
+ dir = AMDTP_OUT_STREAM;
+ }
+
+ err = fw_iso_resources_init(resources, dice->unit);
+ if (err < 0)
+ goto end;
+ resources->channels_mask = 0x00000000ffffffffuLL;
+
+ err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
+ if (err < 0) {
+ amdtp_stream_destroy(stream);
+ fw_iso_resources_destroy(resources);
+ }
+end:
+ return err;
+}
+
+static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ amdtp_stream_destroy(stream);
+
+ if (stream == &dice->tx_stream)
+ fw_iso_resources_destroy(&dice->tx_resources);
+ else
+ fw_iso_resources_destroy(&dice->rx_resources);
+}
+
+int snd_dice_stream_init_duplex(struct snd_dice *dice)
+{
+ int err;
+
+ dice->substreams_counter = 0;
+
+ err = init_stream(dice, &dice->tx_stream);
+ if (err < 0)
+ goto end;
+
+ err = init_stream(dice, &dice->rx_stream);
+end:
+ return err;
+}
+
+void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
+{
+ snd_dice_transaction_clear_enable(dice);
+
+ stop_stream(dice, &dice->tx_stream);
+ destroy_stream(dice, &dice->tx_stream);
+
+ stop_stream(dice, &dice->rx_stream);
+ destroy_stream(dice, &dice->rx_stream);
+
+ dice->substreams_counter = 0;
+}
+
+void snd_dice_stream_update_duplex(struct snd_dice *dice)
+{
+ /*
+ * On a bus reset, the DICE firmware disables streaming and then goes
+ * off contemplating its own navel for hundreds of milliseconds before
+ * it can react to any of our attempts to reenable streaming. This
+ * means that we lose synchronization anyway, so we force our streams
+ * to stop so that the application can restart them in an orderly
+ * manner.
+ */
+ dice->global_enabled = false;
+
+ stop_stream(dice, &dice->rx_stream);
+ stop_stream(dice, &dice->tx_stream);
+
+ fw_iso_resources_update(&dice->rx_resources);
+ fw_iso_resources_update(&dice->tx_resources);
+}
+
+static void dice_lock_changed(struct snd_dice *dice)
+{
+ dice->dev_lock_changed = true;
+ wake_up(&dice->hwdep_wait);
+}
+
+int snd_dice_stream_lock_try(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (dice->dev_lock_count++ == 0)
+ dice_lock_changed(dice);
+ err = 0;
+out:
+ spin_unlock_irq(&dice->lock);
+ return err;
+}
+
+void snd_dice_stream_lock_release(struct snd_dice *dice)
+{
+ spin_lock_irq(&dice->lock);
+
+ if (WARN_ON(dice->dev_lock_count <= 0))
+ goto out;
+
+ if (--dice->dev_lock_count == 0)
+ dice_lock_changed(dice);
+out:
+ spin_unlock_irq(&dice->lock);
+}
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c
new file mode 100644
index 000000000000..aee746187665
--- /dev/null
+++ b/sound/firewire/dice/dice-transaction.c
@@ -0,0 +1,382 @@
+/*
+ * dice_transaction.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+#define NOTIFICATION_TIMEOUT_MS 100
+
+static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
+ u64 offset)
+{
+ switch (type) {
+ case SND_DICE_ADDR_TYPE_TX:
+ offset += dice->tx_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_RX:
+ offset += dice->rx_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_SYNC:
+ offset += dice->sync_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_RSRV:
+ offset += dice->rsrv_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_GLOBAL:
+ default:
+ offset += dice->global_offset;
+ break;
+ }
+ offset += DICE_PRIVATE_SPACE;
+ return offset;
+}
+
+int snd_dice_transaction_write(struct snd_dice *dice,
+ enum snd_dice_addr_type type,
+ unsigned int offset, void *buf, unsigned int len)
+{
+ return snd_fw_transaction(dice->unit,
+ (len == 4) ? TCODE_WRITE_QUADLET_REQUEST :
+ TCODE_WRITE_BLOCK_REQUEST,
+ get_subaddr(dice, type, offset), buf, len, 0);
+}
+
+int snd_dice_transaction_read(struct snd_dice *dice,
+ enum snd_dice_addr_type type, unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_fw_transaction(dice->unit,
+ (len == 4) ? TCODE_READ_QUADLET_REQUEST :
+ TCODE_READ_BLOCK_REQUEST,
+ get_subaddr(dice, type, offset), buf, len, 0);
+}
+
+static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
+{
+ return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
+ info, 4);
+}
+
+static int set_clock_info(struct snd_dice *dice,
+ unsigned int rate, unsigned int source)
+{
+ unsigned int retries = 3;
+ unsigned int i;
+ __be32 info;
+ u32 mask;
+ u32 clock;
+ int err;
+retry:
+ err = get_clock_info(dice, &info);
+ if (err < 0)
+ goto end;
+
+ clock = be32_to_cpu(info);
+ if (source != UINT_MAX) {
+ mask = CLOCK_SOURCE_MASK;
+ clock &= ~mask;
+ clock |= source;
+ }
+ if (rate != UINT_MAX) {
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
+ if (snd_dice_rates[i] == rate)
+ break;
+ }
+ if (i == ARRAY_SIZE(snd_dice_rates)) {
+ err = -EINVAL;
+ goto end;
+ }
+
+ mask = CLOCK_RATE_MASK;
+ clock &= ~mask;
+ clock |= i << CLOCK_RATE_SHIFT;
+ }
+ info = cpu_to_be32(clock);
+
+ if (completion_done(&dice->clock_accepted))
+ reinit_completion(&dice->clock_accepted);
+
+ err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
+ &info, 4);
+ if (err < 0)
+ goto end;
+
+ /* Timeout means it's invalid request, probably bus reset occurred. */
+ if (wait_for_completion_timeout(&dice->clock_accepted,
+ msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
+ if (retries-- == 0) {
+ err = -ETIMEDOUT;
+ goto end;
+ }
+
+ err = snd_dice_transaction_reinit(dice);
+ if (err < 0)
+ goto end;
+
+ msleep(500); /* arbitrary */
+ goto retry;
+ }
+end:
+ return err;
+}
+
+int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
+ unsigned int *source)
+{
+ __be32 info;
+ int err;
+
+ err = get_clock_info(dice, &info);
+ if (err >= 0)
+ *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK;
+
+ return err;
+}
+
+int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
+{
+ __be32 info;
+ unsigned int index;
+ int err;
+
+ err = get_clock_info(dice, &info);
+ if (err < 0)
+ goto end;
+
+ index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
+ if (index >= SND_DICE_RATES_COUNT) {
+ err = -ENOSYS;
+ goto end;
+ }
+
+ *rate = snd_dice_rates[index];
+end:
+ return err;
+}
+int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate)
+{
+ return set_clock_info(dice, rate, UINT_MAX);
+}
+
+int snd_dice_transaction_set_enable(struct snd_dice *dice)
+{
+ __be32 value;
+ int err = 0;
+
+ if (dice->global_enabled)
+ goto end;
+
+ value = cpu_to_be32(1);
+ err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_ENABLE),
+ &value, 4,
+ FW_FIXED_GENERATION | dice->owner_generation);
+ if (err < 0)
+ goto end;
+
+ dice->global_enabled = true;
+end:
+ return err;
+}
+
+void snd_dice_transaction_clear_enable(struct snd_dice *dice)
+{
+ __be32 value;
+
+ value = 0;
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_ENABLE),
+ &value, 4, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ dice->global_enabled = false;
+}
+
+static void dice_notification(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, unsigned long long offset,
+ void *data, size_t length, void *callback_data)
+{
+ struct snd_dice *dice = callback_data;
+ u32 bits;
+ unsigned long flags;
+
+ if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+ if ((offset & 3) != 0) {
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ return;
+ }
+
+ bits = be32_to_cpup(data);
+
+ spin_lock_irqsave(&dice->lock, flags);
+ dice->notification_bits |= bits;
+ spin_unlock_irqrestore(&dice->lock, flags);
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+
+ if (bits & NOTIFY_CLOCK_ACCEPTED)
+ complete(&dice->clock_accepted);
+ wake_up(&dice->hwdep_wait);
+}
+
+static int register_notification_address(struct snd_dice *dice, bool retry)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+ unsigned int retries;
+ int err;
+
+ retries = (retry) ? 3 : 0;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ for (;;) {
+ buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
+ buffer[1] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+
+ dice->owner_generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ get_subaddr(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_OWNER),
+ buffer, 2 * 8,
+ FW_FIXED_GENERATION |
+ dice->owner_generation);
+ if (err == 0) {
+ /* success */
+ if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER))
+ break;
+ /* The address seems to be already registered. */
+ if (buffer[0] == buffer[1])
+ break;
+
+ dev_err(&dice->unit->device,
+ "device is already in use\n");
+ err = -EBUSY;
+ }
+ if (err != -EAGAIN || retries-- > 0)
+ break;
+
+ msleep(20);
+ }
+
+ kfree(buffer);
+
+ if (err < 0)
+ dice->owner_generation = -1;
+
+ return err;
+}
+
+static void unregister_notification_address(struct snd_dice *dice)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (buffer == NULL)
+ return;
+
+ buffer[0] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+ buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
+ snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_OWNER),
+ buffer, 2 * 8, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ kfree(buffer);
+
+ dice->owner_generation = -1;
+}
+
+void snd_dice_transaction_destroy(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+
+ if (handler->callback_data == NULL)
+ return;
+
+ unregister_notification_address(dice);
+
+ fw_core_remove_address_handler(handler);
+ handler->callback_data = NULL;
+}
+
+int snd_dice_transaction_reinit(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+
+ if (handler->callback_data == NULL)
+ return -EINVAL;
+
+ return register_notification_address(dice, false);
+}
+
+int snd_dice_transaction_init(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+ __be32 *pointers;
+ int err;
+
+ /* Use the same way which dice_interface_check() does. */
+ pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL);
+ if (pointers == NULL)
+ return -ENOMEM;
+
+ /* Get offsets for sub-addresses */
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE,
+ pointers, sizeof(__be32) * 10, 0);
+ if (err < 0)
+ goto end;
+
+ /* Allocation callback in address space over host controller */
+ handler->length = 4;
+ handler->address_callback = dice_notification;
+ handler->callback_data = dice;
+ err = fw_core_add_address_handler(handler, &fw_high_memory_region);
+ if (err < 0) {
+ handler->callback_data = NULL;
+ goto end;
+ }
+
+ /* Register the address space */
+ err = register_notification_address(dice, true);
+ if (err < 0) {
+ fw_core_remove_address_handler(handler);
+ handler->callback_data = NULL;
+ goto end;
+ }
+
+ dice->global_offset = be32_to_cpu(pointers[0]) * 4;
+ dice->tx_offset = be32_to_cpu(pointers[2]) * 4;
+ dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
+ dice->sync_offset = be32_to_cpu(pointers[6]) * 4;
+ dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4;
+
+ /* Set up later. */
+ if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4)
+ dice->clock_caps = 1;
+end:
+ kfree(pointers);
+ return err;
+}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
new file mode 100644
index 000000000000..90d8f40ff727
--- /dev/null
+++ b/sound/firewire/dice/dice.c
@@ -0,0 +1,361 @@
+/*
+ * TC Applied Technologies Digital Interface Communications Engine driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+MODULE_DESCRIPTION("DICE driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+#define OUI_WEISS 0x001c6a
+
+#define DICE_CATEGORY_ID 0x04
+#define WEISS_CATEGORY_ID 0x00
+
+static int dice_interface_check(struct fw_unit *unit)
+{
+ static const int min_values[10] = {
+ 10, 0x64 / 4,
+ 10, 0x18 / 4,
+ 10, 0x18 / 4,
+ 0, 0,
+ 0, 0,
+ };
+ struct fw_device *device = fw_parent_device(unit);
+ struct fw_csr_iterator it;
+ int key, val, vendor = -1, model = -1, err;
+ unsigned int category, i;
+ __be32 *pointers, value;
+ __be32 version;
+
+ pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
+ GFP_KERNEL);
+ if (pointers == NULL)
+ return -ENOMEM;
+
+ /*
+ * Check that GUID and unit directory are constructed according to DICE
+ * rules, i.e., that the specifier ID is the GUID's OUI, and that the
+ * GUID chip ID consists of the 8-bit category ID, the 10-bit product
+ * ID, and a 22-bit serial number.
+ */
+ fw_csr_iterator_init(&it, unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &val)) {
+ switch (key) {
+ case CSR_SPECIFIER_ID:
+ vendor = val;
+ break;
+ case CSR_MODEL:
+ model = val;
+ break;
+ }
+ }
+ if (vendor == OUI_WEISS)
+ category = WEISS_CATEGORY_ID;
+ else
+ category = DICE_CATEGORY_ID;
+ if (device->config_rom[3] != ((vendor << 8) | category) ||
+ device->config_rom[4] >> 22 != model) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * Check that the sub address spaces exist and are located inside the
+ * private address space. The minimum values are chosen so that all
+ * minimally required registers are included.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE, pointers,
+ sizeof(__be32) * ARRAY_SIZE(min_values), 0);
+ if (err < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+ for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
+ value = be32_to_cpu(pointers[i]);
+ if (value < min_values[i] || value >= 0x40000) {
+ err = -ENODEV;
+ goto end;
+ }
+ }
+
+ /*
+ * Check that the implemented DICE driver specification major version
+ * number matches.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ DICE_PRIVATE_SPACE +
+ be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
+ &version, 4, 0);
+ if (err < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+ if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
+ dev_err(&unit->device,
+ "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
+ err = -ENODEV;
+ goto end;
+ }
+end:
+ return err;
+}
+
+static int highest_supported_mode_rate(struct snd_dice *dice,
+ unsigned int mode, unsigned int *rate)
+{
+ unsigned int i, m;
+
+ for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) {
+ *rate = snd_dice_rates[i - 1];
+ if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0)
+ continue;
+ if (mode == m)
+ break;
+ }
+ if (i == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
+{
+ __be32 values[2];
+ unsigned int rate;
+ int err;
+
+ if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
+ dice->tx_channels[mode] = 0;
+ dice->tx_midi_ports[mode] = 0;
+ dice->rx_channels[mode] = 0;
+ dice->rx_midi_ports[mode] = 0;
+ return 0;
+ }
+
+ err = snd_dice_transaction_set_rate(dice, rate);
+ if (err < 0)
+ return err;
+
+ err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
+ values, sizeof(values));
+ if (err < 0)
+ return err;
+
+ dice->tx_channels[mode] = be32_to_cpu(values[0]);
+ dice->tx_midi_ports[mode] = be32_to_cpu(values[1]);
+
+ err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
+ values, sizeof(values));
+ if (err < 0)
+ return err;
+
+ dice->rx_channels[mode] = be32_to_cpu(values[0]);
+ dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
+
+ return 0;
+}
+
+static int dice_read_params(struct snd_dice *dice)
+{
+ __be32 value;
+ int mode, err;
+
+ /* some very old firmwares don't tell about their clock support */
+ if (dice->clock_caps > 0) {
+ err = snd_dice_transaction_read_global(dice,
+ GLOBAL_CLOCK_CAPABILITIES,
+ &value, 4);
+ if (err < 0)
+ return err;
+ dice->clock_caps = be32_to_cpu(value);
+ } else {
+ /* this should be supported by any device */
+ dice->clock_caps = CLOCK_CAP_RATE_44100 |
+ CLOCK_CAP_RATE_48000 |
+ CLOCK_CAP_SOURCE_ARX1 |
+ CLOCK_CAP_SOURCE_INTERNAL;
+ }
+
+ for (mode = 2; mode >= 0; --mode) {
+ err = dice_read_mode_params(dice, mode);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void dice_card_strings(struct snd_dice *dice)
+{
+ struct snd_card *card = dice->card;
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ char vendor[32], model[32];
+ unsigned int i;
+ int err;
+
+ strcpy(card->driver, "DICE");
+
+ strcpy(card->shortname, "DICE");
+ BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
+ err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
+ card->shortname,
+ sizeof(card->shortname));
+ if (err >= 0) {
+ /* DICE strings are returned in "always-wrong" endianness */
+ BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
+ for (i = 0; i < sizeof(card->shortname); i += 4)
+ swab32s((u32 *)&card->shortname[i]);
+ card->shortname[sizeof(card->shortname) - 1] = '\0';
+ }
+
+ strcpy(vendor, "?");
+ fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
+ strcpy(model, "?");
+ fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s %s (serial %u) at %s, S%d",
+ vendor, model, dev->config_rom[4] & 0x3fffff,
+ dev_name(&dice->unit->device), 100 << dev->max_speed);
+
+ strcpy(card->mixername, "DICE");
+}
+
+static void dice_card_free(struct snd_card *card)
+{
+ struct snd_dice *dice = card->private_data;
+
+ snd_dice_transaction_destroy(dice);
+ mutex_destroy(&dice->mutex);
+}
+
+static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+{
+ struct snd_card *card;
+ struct snd_dice *dice;
+ int err;
+
+ err = dice_interface_check(unit);
+ if (err < 0)
+ goto end;
+
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*dice), &card);
+ if (err < 0)
+ goto end;
+
+ dice = card->private_data;
+ dice->card = card;
+ dice->unit = unit;
+ card->private_free = dice_card_free;
+
+ spin_lock_init(&dice->lock);
+ mutex_init(&dice->mutex);
+ init_completion(&dice->clock_accepted);
+ init_waitqueue_head(&dice->hwdep_wait);
+
+ err = snd_dice_transaction_init(dice);
+ if (err < 0)
+ goto error;
+
+ err = dice_read_params(dice);
+ if (err < 0)
+ goto error;
+
+ dice_card_strings(dice);
+
+ err = snd_dice_create_pcm(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_dice_create_hwdep(dice);
+ if (err < 0)
+ goto error;
+
+ snd_dice_create_proc(dice);
+
+ err = snd_dice_create_midi(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_dice_stream_init_duplex(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_dice_stream_destroy_duplex(dice);
+ goto error;
+ }
+
+ dev_set_drvdata(&unit->device, dice);
+end:
+ return err;
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static void dice_remove(struct fw_unit *unit)
+{
+ struct snd_dice *dice = dev_get_drvdata(&unit->device);
+
+ snd_card_disconnect(dice->card);
+
+ snd_dice_stream_destroy_duplex(dice);
+
+ snd_card_free_when_closed(dice->card);
+}
+
+static void dice_bus_reset(struct fw_unit *unit)
+{
+ struct snd_dice *dice = dev_get_drvdata(&unit->device);
+
+ /* The handler address register becomes initialized. */
+ snd_dice_transaction_reinit(dice);
+
+ mutex_lock(&dice->mutex);
+ snd_dice_stream_update_duplex(dice);
+ mutex_unlock(&dice->mutex);
+}
+
+#define DICE_INTERFACE 0x000001
+
+static const struct ieee1394_device_id dice_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VERSION,
+ .version = DICE_INTERFACE,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
+
+static struct fw_driver dice_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = dice_probe,
+ .update = dice_bus_reset,
+ .remove = dice_remove,
+ .id_table = dice_id_table,
+};
+
+static int __init alsa_dice_init(void)
+{
+ return driver_register(&dice_driver.driver);
+}
+
+static void __exit alsa_dice_exit(void)
+{
+ driver_unregister(&dice_driver.driver);
+}
+
+module_init(alsa_dice_init);
+module_exit(alsa_dice_exit);
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
new file mode 100644
index 000000000000..ecf5dc862235
--- /dev/null
+++ b/sound/firewire/dice/dice.h
@@ -0,0 +1,189 @@
+/*
+ * dice.h - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef SOUND_DICE_H_INCLUDED
+#define SOUND_DICE_H_INCLUDED
+
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rawmidi.h>
+
+#include "../amdtp.h"
+#include "../iso-resources.h"
+#include "../lib.h"
+#include "dice-interface.h"
+
+struct snd_dice {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ spinlock_t lock;
+ struct mutex mutex;
+
+ /* Offsets for sub-addresses */
+ unsigned int global_offset;
+ unsigned int rx_offset;
+ unsigned int tx_offset;
+ unsigned int sync_offset;
+ unsigned int rsrv_offset;
+
+ unsigned int clock_caps;
+ unsigned int tx_channels[3];
+ unsigned int rx_channels[3];
+ unsigned int tx_midi_ports[3];
+ unsigned int rx_midi_ports[3];
+
+ struct fw_address_handler notification_handler;
+ int owner_generation;
+ u32 notification_bits;
+
+ /* For uapi */
+ int dev_lock_count; /* > 0 driver, < 0 userspace */
+ bool dev_lock_changed;
+ wait_queue_head_t hwdep_wait;
+
+ /* For streaming */
+ struct fw_iso_resources tx_resources;
+ struct fw_iso_resources rx_resources;
+ struct amdtp_stream tx_stream;
+ struct amdtp_stream rx_stream;
+ bool global_enabled;
+ struct completion clock_accepted;
+ unsigned int substreams_counter;
+};
+
+enum snd_dice_addr_type {
+ SND_DICE_ADDR_TYPE_PRIVATE,
+ SND_DICE_ADDR_TYPE_GLOBAL,
+ SND_DICE_ADDR_TYPE_TX,
+ SND_DICE_ADDR_TYPE_RX,
+ SND_DICE_ADDR_TYPE_SYNC,
+ SND_DICE_ADDR_TYPE_RSRV,
+};
+
+int snd_dice_transaction_write(struct snd_dice *dice,
+ enum snd_dice_addr_type type,
+ unsigned int offset,
+ void *buf, unsigned int len);
+int snd_dice_transaction_read(struct snd_dice *dice,
+ enum snd_dice_addr_type type, unsigned int offset,
+ void *buf, unsigned int len);
+
+static inline int snd_dice_transaction_write_global(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_global(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_tx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_TX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_tx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_TX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_rx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_RX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_rx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_RX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_sync(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_SYNC, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_sync(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_SYNC, offset,
+ buf, len);
+}
+
+int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
+ unsigned int *source);
+int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate);
+int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate);
+int snd_dice_transaction_set_enable(struct snd_dice *dice);
+void snd_dice_transaction_clear_enable(struct snd_dice *dice);
+int snd_dice_transaction_init(struct snd_dice *dice);
+int snd_dice_transaction_reinit(struct snd_dice *dice);
+void snd_dice_transaction_destroy(struct snd_dice *dice);
+
+#define SND_DICE_RATES_COUNT 7
+extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
+
+int snd_dice_stream_get_rate_mode(struct snd_dice *dice,
+ unsigned int rate, unsigned int *mode);
+
+int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
+void snd_dice_stream_stop_duplex(struct snd_dice *dice);
+int snd_dice_stream_init_duplex(struct snd_dice *dice);
+void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
+void snd_dice_stream_update_duplex(struct snd_dice *dice);
+
+int snd_dice_stream_lock_try(struct snd_dice *dice);
+void snd_dice_stream_lock_release(struct snd_dice *dice);
+
+int snd_dice_create_pcm(struct snd_dice *dice);
+
+int snd_dice_create_hwdep(struct snd_dice *dice);
+
+void snd_dice_create_proc(struct snd_dice *dice);
+
+int snd_dice_create_midi(struct snd_dice *dice);
+
+#endif
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 7ac94439e758..48d6dca471c6 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -131,14 +131,8 @@ static void isight_samples(struct isight *isight,
static void isight_pcm_abort(struct isight *isight)
{
- unsigned long flags;
-
- if (ACCESS_ONCE(isight->pcm_active)) {
- snd_pcm_stream_lock_irqsave(isight->pcm, flags);
- if (snd_pcm_running(isight->pcm))
- snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
- }
+ if (ACCESS_ONCE(isight->pcm_active))
+ snd_pcm_stop_xrun(isight->pcm);
}
static void isight_dropped_samples(struct isight *isight, unsigned int total)
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
new file mode 100644
index 000000000000..a926850864f6
--- /dev/null
+++ b/sound/firewire/oxfw/Makefile
@@ -0,0 +1,3 @@
+snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
+ oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o
+obj-m += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-command.c b/sound/firewire/oxfw/oxfw-command.c
new file mode 100644
index 000000000000..12ef3253bc89
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-command.c
@@ -0,0 +1,153 @@
+/*
+ * oxfw_command.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *format, unsigned int len)
+{
+ u8 *buf;
+ int err;
+
+ buf = kmalloc(len + 10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf[0] = 0x00; /* CONTROL */
+ buf[1] = 0xff; /* UNIT */
+ buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */
+ buf[3] = 0xc0; /* SINGLE subfunction */
+ buf[4] = dir; /* Plug Direction */
+ buf[5] = 0x00; /* UNIT */
+ buf[6] = 0x00; /* PCR (Isochronous Plug) */
+ buf[7] = 0xff & pid; /* Plug ID */
+ buf[8] = 0xff; /* Padding */
+ buf[9] = 0xff; /* Support status in response */
+ memcpy(buf + 10, format, len);
+
+ /* do transaction and check buf[1-8] are the same against command */
+ err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+ BIT(6) | BIT(7) | BIT(8));
+ if ((err > 0) && (err < len + 10))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ else if (buf[0] == 0x0a) /* REJECTED */
+ err = -EINVAL;
+ else
+ err = 0;
+
+ kfree(buf);
+
+ return err;
+}
+
+int avc_stream_get_format(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len, unsigned int eid)
+{
+ unsigned int subfunc;
+ int err;
+
+ if (eid == 0xff)
+ subfunc = 0xc0; /* SINGLE */
+ else
+ subfunc = 0xc1; /* LIST */
+
+ buf[0] = 0x01; /* STATUS */
+ buf[1] = 0xff; /* UNIT */
+ buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */
+ buf[3] = subfunc; /* SINGLE or LIST */
+ buf[4] = dir; /* Plug Direction */
+ buf[5] = 0x00; /* Unit */
+ buf[6] = 0x00; /* PCR (Isochronous Plug) */
+ buf[7] = 0xff & pid; /* Plug ID */
+ buf[8] = 0xff; /* Padding */
+ buf[9] = 0xff; /* support status in response */
+ buf[10] = 0xff & eid; /* entry ID for LIST subfunction */
+ buf[11] = 0xff; /* padding */
+
+ /* do transaction and check buf[1-7] are the same against command */
+ err = fcp_avc_transaction(unit, buf, 12, buf, *len,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+ BIT(6) | BIT(7));
+ if ((err > 0) && (err < 10))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ else if (buf[0] == 0x0a) /* REJECTED */
+ err = -EINVAL;
+ else if (buf[0] == 0x0b) /* IN TRANSITION */
+ err = -EAGAIN;
+ /* LIST subfunction has entry ID */
+ else if ((subfunc == 0xc1) && (buf[10] != eid))
+ err = -EIO;
+ if (err < 0)
+ goto end;
+
+ /* keep just stream format information */
+ if (subfunc == 0xc0) {
+ memmove(buf, buf + 10, err - 10);
+ *len = err - 10;
+ } else {
+ memmove(buf, buf + 11, err - 11);
+ *len = err - 11;
+ }
+
+ err = 0;
+end:
+ return err;
+}
+
+int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
+ enum avc_general_plug_dir dir,
+ unsigned short pid)
+{
+ unsigned int sfc;
+ u8 *buf;
+ int err;
+
+ for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
+ if (amdtp_rate_table[sfc] == rate)
+ break;
+ }
+ if (sfc == CIP_SFC_COUNT)
+ return -EINVAL;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf[0] = 0x02; /* SPECIFIC INQUIRY */
+ buf[1] = 0xff; /* UNIT */
+ if (dir == AVC_GENERAL_PLUG_DIR_IN)
+ buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
+ else
+ buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
+ buf[3] = 0xff & pid; /* plug id */
+ buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
+ buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */
+ buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */
+ buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
+
+ /* do transaction and check buf[1-5] are the same against command */
+ err = fcp_avc_transaction(unit, buf, 8, buf, 8,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
+ if ((err > 0) && (err < 8))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ if (err < 0)
+ goto end;
+
+ err = 0;
+end:
+ kfree(buf);
+ return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-control.c
new file mode 100644
index 000000000000..02a1cb90f20d
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-control.c
@@ -0,0 +1,283 @@
+/*
+ * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+enum control_action { CTL_READ, CTL_WRITE };
+enum control_attribute {
+ CTL_MIN = 0x02,
+ CTL_MAX = 0x03,
+ CTL_CURRENT = 0x10,
+};
+
+static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(11, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */
+ buf[5] = 0x10; /* control attribute: current */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = 0x00; /* audio channel number */
+ buf[8] = 0x01; /* control selector: mute */
+ buf[9] = 0x01; /* control data length */
+ if (action == CTL_READ)
+ buf[10] = 0xff;
+ else
+ buf[10] = *value ? 0x70 : 0x60;
+
+ err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 11) {
+ dev_err(&oxfw->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&oxfw->unit->device, "mute command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = buf[10] == 0x70;
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
+ unsigned int channel,
+ enum control_attribute attribute,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(12, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */
+ buf[5] = attribute; /* control attribute */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = channel; /* audio channel number */
+ buf[8] = 0x02; /* control selector: volume */
+ buf[9] = 0x02; /* control data length */
+ if (action == CTL_READ) {
+ buf[10] = 0xff;
+ buf[11] = 0xff;
+ } else {
+ buf[10] = *value >> 8;
+ buf[11] = *value;
+ }
+
+ err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 12) {
+ dev_err(&oxfw->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&oxfw->unit->device, "volume command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = (buf[10] << 8) | buf[11];
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int oxfw_mute_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+
+ value->value.integer.value[0] = !oxfw->mute;
+
+ return 0;
+}
+
+static int oxfw_mute_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ bool mute;
+ int err;
+
+ mute = !value->value.integer.value[0];
+
+ if (mute == oxfw->mute)
+ return 0;
+
+ err = oxfw_mute_command(oxfw, &mute, CTL_WRITE);
+ if (err < 0)
+ return err;
+ oxfw->mute = mute;
+
+ return 1;
+}
+
+static int oxfw_volume_info(struct snd_kcontrol *control,
+ struct snd_ctl_elem_info *info)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = oxfw->device_info->mixer_channels;
+ info->value.integer.min = oxfw->volume_min;
+ info->value.integer.max = oxfw->volume_max;
+
+ return 0;
+}
+
+static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
+
+static int oxfw_volume_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ unsigned int i;
+
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
+ value->value.integer.value[channel_map[i]] = oxfw->volume[i];
+
+ return 0;
+}
+
+static int oxfw_volume_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ unsigned int i, changed_channels;
+ bool equal_values = true;
+ s16 volume;
+ int err;
+
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
+ if (value->value.integer.value[i] < oxfw->volume_min ||
+ value->value.integer.value[i] > oxfw->volume_max)
+ return -EINVAL;
+ if (value->value.integer.value[i] !=
+ value->value.integer.value[0])
+ equal_values = false;
+ }
+
+ changed_channels = 0;
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
+ if (value->value.integer.value[channel_map[i]] !=
+ oxfw->volume[i])
+ changed_channels |= 1 << (i + 1);
+
+ if (equal_values && changed_channels != 0)
+ changed_channels = 1 << 0;
+
+ for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) {
+ volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
+ if (changed_channels & (1 << i)) {
+ err = oxfw_volume_command(oxfw, &volume, i,
+ CTL_CURRENT, CTL_WRITE);
+ if (err < 0)
+ return err;
+ }
+ if (i > 0)
+ oxfw->volume[i - 1] = volume;
+ }
+
+ return changed_channels != 0;
+}
+
+int snd_oxfw_create_mixer(struct snd_oxfw *oxfw)
+{
+ static const struct snd_kcontrol_new controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = oxfw_mute_get,
+ .put = oxfw_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = oxfw_volume_info,
+ .get = oxfw_volume_get,
+ .put = oxfw_volume_put,
+ },
+ };
+ unsigned int i, first_ch;
+ int err;
+
+ err = oxfw_volume_command(oxfw, &oxfw->volume_min,
+ 0, CTL_MIN, CTL_READ);
+ if (err < 0)
+ return err;
+ err = oxfw_volume_command(oxfw, &oxfw->volume_max,
+ 0, CTL_MAX, CTL_READ);
+ if (err < 0)
+ return err;
+
+ err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ);
+ if (err < 0)
+ return err;
+
+ first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1;
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
+ err = oxfw_volume_command(oxfw, &oxfw->volume[i],
+ first_ch + i, CTL_CURRENT, CTL_READ);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(controls); ++i) {
+ err = snd_ctl_add(oxfw->card,
+ snd_ctl_new1(&controls[i], oxfw));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c
new file mode 100644
index 000000000000..ff2687ad0460
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-hwdep.c
@@ -0,0 +1,190 @@
+/*
+ * oxfw_hwdep.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes give three functionality.
+ *
+ * 1.get firewire node information
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock stream
+ */
+
+#include "oxfw.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
+ loff_t *offset)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&oxfw->lock);
+
+ while (!oxfw->dev_lock_changed) {
+ prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&oxfw->lock);
+ schedule();
+ finish_wait(&oxfw->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&oxfw->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (oxfw->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = (oxfw->dev_lock_count > 0);
+ oxfw->dev_lock_changed = false;
+
+ count = min_t(long, count, sizeof(event.lock_status));
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &oxfw->hwdep_wait, wait);
+
+ spin_lock_irq(&oxfw->lock);
+ if (oxfw->dev_lock_changed)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&oxfw->lock);
+
+ return events;
+}
+
+static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(oxfw->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_OXFW;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int hwdep_lock(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ if (oxfw->dev_lock_count == 0) {
+ oxfw->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ return err;
+}
+
+static int hwdep_unlock(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ if (oxfw->dev_lock_count == -1) {
+ oxfw->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+
+ spin_lock_irq(&oxfw->lock);
+ if (oxfw->dev_lock_count == -1)
+ oxfw->dev_lock_count = 0;
+ spin_unlock_irq(&oxfw->lock);
+
+ return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return hwdep_get_info(oxfw, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return hwdep_lock(oxfw);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return hwdep_unlock(oxfw);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
+{
+ static const struct snd_hwdep_ops hwdep_ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
+ struct snd_hwdep *hwdep;
+ int err;
+
+ err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
+ if (err < 0)
+ goto end;
+ strcpy(hwdep->name, oxfw->card->driver);
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
+ hwdep->ops = hwdep_ops;
+ hwdep->private_data = oxfw;
+ hwdep->exclusive = true;
+end:
+ return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
new file mode 100644
index 000000000000..540a30338516
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -0,0 +1,207 @@
+/*
+ * oxfw_midi.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+static int midi_capture_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->capture_substreams++;
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0);
+
+ mutex_unlock(&oxfw->mutex);
+
+ if (err < 0)
+ snd_oxfw_stream_lock_release(oxfw);
+
+ return err;
+}
+
+static int midi_playback_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->playback_substreams++;
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0);
+
+ mutex_unlock(&oxfw->mutex);
+
+ if (err < 0)
+ snd_oxfw_stream_lock_release(oxfw);
+
+ return err;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->capture_substreams--;
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->playback_substreams--;
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_oxfw *oxfw = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxfw->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&oxfw->tx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&oxfw->tx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&oxfw->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_oxfw *oxfw = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxfw->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&oxfw->rx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&oxfw->rx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&oxfw->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_oxfw *oxfw,
+ struct snd_rawmidi_str *str)
+{
+ struct snd_rawmidi_substream *subs;
+
+ list_for_each_entry(subs, &str->substreams, list) {
+ snprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ oxfw->card->shortname, subs->number + 1);
+ }
+}
+
+int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
+{
+ struct snd_oxfw_stream_formation formation;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *str;
+ u8 *format;
+ int i, err;
+
+ /* If its stream has MIDI conformant data channel, add one MIDI port */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->tx_stream_formats[i];
+ if (format != NULL) {
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err >= 0 && formation.midi > 0)
+ oxfw->midi_input_ports = 1;
+ }
+
+ format = oxfw->rx_stream_formats[i];
+ if (format != NULL) {
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err >= 0 && formation.midi > 0)
+ oxfw->midi_output_ports = 1;
+ }
+ }
+ if ((oxfw->midi_input_ports == 0) && (oxfw->midi_output_ports == 0))
+ return 0;
+
+ /* create midi ports */
+ err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
+ oxfw->midi_output_ports, oxfw->midi_input_ports,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", oxfw->card->shortname);
+ rmidi->private_data = oxfw;
+
+ if (oxfw->midi_input_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &midi_capture_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+
+ set_midi_substream_names(oxfw, str);
+ }
+
+ if (oxfw->midi_output_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &midi_playback_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+
+ set_midi_substream_names(oxfw, str);
+ }
+
+ if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
new file mode 100644
index 000000000000..67ade0775a5b
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -0,0 +1,424 @@
+/*
+ * oxfw_pcm.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+static int hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ u8 **formats = rule->private;
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ const struct snd_interval *c =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval t = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ struct snd_oxfw_stream_formation formation;
+ int i, err;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+ if (!snd_interval_test(c, formation.pcm))
+ continue;
+
+ t.min = min(t.min, formation.rate);
+ t.max = max(t.max, formation.rate);
+
+ }
+ return snd_interval_refine(r, &t);
+}
+
+static int hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ u8 **formats = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ const struct snd_interval *r =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_oxfw_stream_formation formation;
+ int i, j, err;
+ unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0};
+
+ count = 0;
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+ if (!snd_interval_test(r, formation.rate))
+ continue;
+ if (list[count] == formation.pcm)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(list); j++) {
+ if (list[j] == formation.pcm)
+ break;
+ }
+ if (j == ARRAY_SIZE(list)) {
+ list[count] = formation.pcm;
+ if (++count == ARRAY_SIZE(list))
+ break;
+ }
+ }
+
+ return snd_interval_list(c, count, list, 0);
+}
+
+static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats)
+{
+ struct snd_oxfw_stream_formation formation;
+ int i, err;
+
+ hw->channels_min = UINT_MAX;
+ hw->channels_max = 0;
+
+ hw->rate_min = UINT_MAX;
+ hw->rate_max = 0;
+ hw->rates = 0;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+
+ hw->channels_min = min(hw->channels_min, formation.pcm);
+ hw->channels_max = max(hw->channels_max, formation.pcm);
+
+ hw->rate_min = min(hw->rate_min, formation.rate);
+ hw->rate_max = max(hw->rate_max, formation.rate);
+ hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate);
+ }
+}
+
+static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
+{
+ hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
+ hw->periods_max = UINT_MAX;
+
+ hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */
+
+ /* Just to prevent from allocating much pages. */
+ hw->period_bytes_max = hw->period_bytes_min * 2048;
+ hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
+}
+
+static int init_hw_params(struct snd_oxfw *oxfw,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u8 **formats;
+ struct amdtp_stream *stream;
+ int err;
+
+ runtime->hw.info = SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+ stream = &oxfw->tx_stream;
+ formats = oxfw->tx_stream_formats;
+ } else {
+ runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+ stream = &oxfw->rx_stream;
+ formats = oxfw->rx_stream_formats;
+ }
+
+ limit_channels_and_rates(&runtime->hw, formats);
+ limit_period_and_buffer(&runtime->hw);
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_channels, formats,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto end;
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ hw_rule_rate, formats,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+end:
+ return err;
+}
+
+static int limit_to_current_params(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ int err;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ else
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+ if (err < 0)
+ goto end;
+
+ substream->runtime->hw.channels_min = formation.pcm;
+ substream->runtime->hw.channels_max = formation.pcm;
+ substream->runtime->hw.rate_min = formation.rate;
+ substream->runtime->hw.rate_max = formation.rate;
+end:
+ return err;
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ goto end;
+
+ err = init_hw_params(oxfw, substream);
+ if (err < 0)
+ goto err_locked;
+
+ /*
+ * When any PCM streams are already running, the available sampling
+ * rate is limited at current value.
+ */
+ if (amdtp_stream_pcm_running(&oxfw->tx_stream) ||
+ amdtp_stream_pcm_running(&oxfw->rx_stream)) {
+ err = limit_to_current_params(substream);
+ if (err < 0)
+ goto end;
+ }
+
+ snd_pcm_set_sync(substream);
+end:
+ return err;
+err_locked:
+ snd_oxfw_stream_lock_release(oxfw);
+ return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&oxfw->mutex);
+ oxfw->capture_substreams++;
+ mutex_unlock(&oxfw->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&oxfw->mutex);
+ oxfw->playback_substreams++;
+ mutex_unlock(&oxfw->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ oxfw->capture_substreams--;
+
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ oxfw->playback_substreams--;
+
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ mutex_lock(&oxfw->mutex);
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream,
+ runtime->rate, runtime->channels);
+ mutex_unlock(&oxfw->mutex);
+ if (err < 0)
+ goto end;
+
+ amdtp_stream_pcm_prepare(&oxfw->tx_stream);
+end:
+ return err;
+}
+static int pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ mutex_lock(&oxfw->mutex);
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
+ runtime->rate, runtime->channels);
+ mutex_unlock(&oxfw->mutex);
+ if (err < 0)
+ goto end;
+
+ amdtp_stream_pcm_prepare(&oxfw->rx_stream);
+end:
+ return err;
+}
+
+static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm);
+ return 0;
+}
+static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
+ return 0;
+}
+
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
+{
+ struct snd_oxfw *oxfw = sbstm->private_data;
+
+ return amdtp_stream_pcm_pointer(&oxfw->tx_stream);
+}
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
+{
+ struct snd_oxfw *oxfw = sbstm->private_data;
+
+ return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
+}
+
+int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
+{
+ static struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ static struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ unsigned int cap = 0;
+ int err;
+
+ if (oxfw->has_output)
+ cap = 1;
+
+ err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm);
+ if (err < 0)
+ return err;
+
+ pcm->private_data = oxfw;
+ strcpy(pcm->name, oxfw->card->shortname);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ if (cap > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c
new file mode 100644
index 000000000000..8ba4f9f262b8
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-proc.c
@@ -0,0 +1,113 @@
+/*
+ * oxfw_proc.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./oxfw.h"
+
+static void proc_read_formation(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_oxfw *oxfw = entry->private_data;
+ struct snd_oxfw_stream_formation formation, curr;
+ u8 *format;
+ char flag;
+ int i, err;
+
+ /* Show input. */
+ err = snd_oxfw_stream_get_current_formation(oxfw,
+ AVC_GENERAL_PLUG_DIR_IN,
+ &curr);
+ if (err < 0)
+ return;
+
+ snd_iprintf(buffer, "Input Stream to device:\n");
+ snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->rx_stream_formats[i];
+ if (format == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err < 0)
+ continue;
+
+ if (memcmp(&formation, &curr, sizeof(curr)) == 0)
+ flag = '*';
+ else
+ flag = ' ';
+
+ snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
+ formation.rate, formation.pcm, formation.midi);
+ }
+
+ if (!oxfw->has_output)
+ return;
+
+ /* Show output. */
+ err = snd_oxfw_stream_get_current_formation(oxfw,
+ AVC_GENERAL_PLUG_DIR_OUT,
+ &curr);
+ if (err < 0)
+ return;
+
+ snd_iprintf(buffer, "Output Stream from device:\n");
+ snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->tx_stream_formats[i];
+ if (format == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err < 0)
+ continue;
+
+ if (memcmp(&formation, &curr, sizeof(curr)) == 0)
+ flag = '*';
+ else
+ flag = ' ';
+
+ snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
+ formation.rate, formation.pcm, formation.midi);
+ }
+}
+
+static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root,
+ const char *name,
+ void (*op)(struct snd_info_entry *e,
+ struct snd_info_buffer *b))
+{
+ struct snd_info_entry *entry;
+
+ entry = snd_info_create_card_entry(oxfw->card, name, root);
+ if (entry == NULL)
+ return;
+
+ snd_info_set_text_ops(entry, oxfw, op);
+ if (snd_info_register(entry) < 0)
+ snd_info_free_entry(entry);
+}
+
+void snd_oxfw_proc_init(struct snd_oxfw *oxfw)
+{
+ struct snd_info_entry *root;
+
+ /*
+ * All nodes are automatically removed at snd_card_disconnect(),
+ * by following to link list.
+ */
+ root = snd_info_create_card_entry(oxfw->card, "firewire",
+ oxfw->card->proc_root);
+ if (root == NULL)
+ return;
+ root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ if (snd_info_register(root) < 0) {
+ snd_info_free_entry(root);
+ return;
+ }
+
+ add_node(oxfw, root, "formation", proc_read_formation);
+}
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
new file mode 100644
index 000000000000..bda845afb470
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -0,0 +1,686 @@
+/*
+ * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+#include <linux/delay.h>
+
+#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
+#define CALLBACK_TIMEOUT 200
+
+/*
+ * According to datasheet of Oxford Semiconductor:
+ * OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
+ * OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
+ */
+static const unsigned int oxfw_rate_table[] = {
+ [0] = 32000,
+ [1] = 44100,
+ [2] = 48000,
+ [3] = 88200,
+ [4] = 96000,
+ [5] = 192000,
+};
+
+/*
+ * See Table 5.7 – Sampling frequency for Multi-bit Audio
+ * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
+ */
+static const unsigned int avc_stream_rate_table[] = {
+ [0] = 0x02,
+ [1] = 0x03,
+ [2] = 0x04,
+ [3] = 0x0a,
+ [4] = 0x05,
+ [5] = 0x07,
+};
+
+static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
+{
+ int err;
+
+ err = avc_general_set_sig_fmt(oxfw->unit, rate,
+ AVC_GENERAL_PLUG_DIR_IN, 0);
+ if (err < 0)
+ goto end;
+
+ if (oxfw->has_output)
+ err = avc_general_set_sig_fmt(oxfw->unit, rate,
+ AVC_GENERAL_PLUG_DIR_OUT, 0);
+end:
+ return err;
+}
+
+static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ u8 **formats;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ unsigned int len;
+ int i, err;
+
+ if (s == &oxfw->tx_stream) {
+ formats = oxfw->tx_stream_formats;
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ } else {
+ formats = oxfw->rx_stream_formats;
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+ }
+
+ /* Seek stream format for requirements. */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ return err;
+
+ if ((formation.rate == rate) && (formation.pcm == pcm_channels))
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+ return -EINVAL;
+
+ /* If assumed, just change rate. */
+ if (oxfw->assumed)
+ return set_rate(oxfw, rate);
+
+ /* Calculate format length. */
+ len = 5 + formats[i][4] * 2;
+
+ err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
+ if (err < 0)
+ return err;
+
+ /* Some requests just after changing format causes freezing. */
+ msleep(100);
+
+ return 0;
+}
+
+static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
+{
+ amdtp_stream_pcm_abort(stream);
+ amdtp_stream_stop(stream);
+
+ if (stream == &oxfw->tx_stream)
+ cmp_connection_break(&oxfw->out_conn);
+ else
+ cmp_connection_break(&oxfw->in_conn);
+}
+
+static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ u8 **formats;
+ struct cmp_connection *conn;
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, midi_ports;
+ int err;
+
+ if (stream == &oxfw->rx_stream) {
+ formats = oxfw->rx_stream_formats;
+ conn = &oxfw->in_conn;
+ } else {
+ formats = oxfw->tx_stream_formats;
+ conn = &oxfw->out_conn;
+ }
+
+ /* Get stream format */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ goto end;
+ if (rate != formation.rate)
+ continue;
+ if (pcm_channels == 0 || pcm_channels == formation.pcm)
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
+ err = -EINVAL;
+ goto end;
+ }
+
+ pcm_channels = formation.pcm;
+ midi_ports = DIV_ROUND_UP(formation.midi, 8);
+
+ /* The stream should have one pcm channels at least */
+ if (pcm_channels == 0) {
+ err = -EINVAL;
+ goto end;
+ }
+ amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
+
+ err = cmp_connection_establish(conn,
+ amdtp_stream_get_max_payload(stream));
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_start(stream,
+ conn->resources.channel,
+ conn->speed);
+ if (err < 0) {
+ cmp_connection_break(conn);
+ goto end;
+ }
+
+ /* Wait first packet */
+ err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
+ if (err < 0)
+ stop_stream(oxfw, stream);
+end:
+ return err;
+}
+
+static int check_connection_used_by_others(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+ bool used;
+ int err;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ err = cmp_connection_check_used(conn, &used);
+ if ((err >= 0) && used && !amdtp_stream_running(stream)) {
+ dev_err(&oxfw->unit->device,
+ "Connection established by others: %cPCR[%d]\n",
+ (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
+ conn->pcr_index);
+ err = -EBUSY;
+ }
+
+ return err;
+}
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+ enum cmp_direction c_dir;
+ enum amdtp_stream_direction s_dir;
+ int err;
+
+ if (stream == &oxfw->tx_stream) {
+ conn = &oxfw->out_conn;
+ c_dir = CMP_OUTPUT;
+ s_dir = AMDTP_IN_STREAM;
+ } else {
+ conn = &oxfw->in_conn;
+ c_dir = CMP_INPUT;
+ s_dir = AMDTP_OUT_STREAM;
+ }
+
+ err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
+ if (err < 0) {
+ amdtp_stream_destroy(stream);
+ cmp_connection_destroy(conn);
+ goto end;
+ }
+
+ /* OXFW starts to transmit packets with non-zero dbc. */
+ if (stream == &oxfw->tx_stream)
+ oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
+end:
+ return err;
+}
+
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ struct amdtp_stream *opposite;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ unsigned int substreams, opposite_substreams;
+ int err = 0;
+
+ if (stream == &oxfw->tx_stream) {
+ substreams = oxfw->capture_substreams;
+ opposite = &oxfw->rx_stream;
+ opposite_substreams = oxfw->playback_substreams;
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ } else {
+ substreams = oxfw->playback_substreams;
+ opposite_substreams = oxfw->capture_substreams;
+
+ if (oxfw->has_output)
+ opposite = &oxfw->rx_stream;
+ else
+ opposite = NULL;
+
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+ }
+
+ if (substreams == 0)
+ goto end;
+
+ /*
+ * Considering JACK/FFADO streaming:
+ * TODO: This can be removed hwdep functionality becomes popular.
+ */
+ err = check_connection_used_by_others(oxfw, stream);
+ if (err < 0)
+ goto end;
+
+ /* packet queueing error */
+ if (amdtp_streaming_error(stream))
+ stop_stream(oxfw, stream);
+
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+ if (err < 0)
+ goto end;
+ if (rate == 0)
+ rate = formation.rate;
+ if (pcm_channels == 0)
+ pcm_channels = formation.pcm;
+
+ if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
+ if (opposite != NULL) {
+ err = check_connection_used_by_others(oxfw, opposite);
+ if (err < 0)
+ goto end;
+ stop_stream(oxfw, opposite);
+ }
+ stop_stream(oxfw, stream);
+
+ err = set_stream_format(oxfw, stream, rate, pcm_channels);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to set stream format: %d\n", err);
+ goto end;
+ }
+
+ /* Start opposite stream if needed. */
+ if (opposite && !amdtp_stream_running(opposite) &&
+ (opposite_substreams > 0)) {
+ err = start_stream(oxfw, opposite, rate, 0);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to restart stream: %d\n", err);
+ goto end;
+ }
+ }
+ }
+
+ /* Start requested stream. */
+ if (!amdtp_stream_running(stream)) {
+ err = start_stream(oxfw, stream, rate, pcm_channels);
+ if (err < 0)
+ dev_err(&oxfw->unit->device,
+ "fail to start stream: %d\n", err);
+ }
+end:
+ return err;
+}
+
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
+ ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
+ return;
+
+ stop_stream(oxfw, stream);
+}
+
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ stop_stream(oxfw, stream);
+
+ amdtp_stream_destroy(stream);
+ cmp_connection_destroy(conn);
+}
+
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ if (cmp_connection_update(conn) < 0)
+ stop_stream(oxfw, stream);
+ else
+ amdtp_stream_update(stream);
+}
+
+int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ struct snd_oxfw_stream_formation *formation)
+{
+ u8 *format;
+ unsigned int len;
+ int err;
+
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ format = kmalloc(len, GFP_KERNEL);
+ if (format == NULL)
+ return -ENOMEM;
+
+ err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
+ if (err < 0)
+ goto end;
+ if (len < 3) {
+ err = -EIO;
+ goto end;
+ }
+
+ err = snd_oxfw_stream_parse_format(format, formation);
+end:
+ kfree(format);
+ return err;
+}
+
+/*
+ * See Table 6.16 - AM824 Stream Format
+ * Figure 6.19 - format_information field for AM824 Compound
+ * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
+ * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
+ */
+int snd_oxfw_stream_parse_format(u8 *format,
+ struct snd_oxfw_stream_formation *formation)
+{
+ unsigned int i, e, channels, type;
+
+ memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
+
+ /*
+ * this module can support a hierarchy combination that:
+ * Root: Audio and Music (0x90)
+ * Level 1: AM824 Compound (0x40)
+ */
+ if ((format[0] != 0x90) || (format[1] != 0x40))
+ return -ENOSYS;
+
+ /* check the sampling rate */
+ for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
+ if (format[2] == avc_stream_rate_table[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(avc_stream_rate_table))
+ return -ENOSYS;
+
+ formation->rate = oxfw_rate_table[i];
+
+ for (e = 0; e < format[4]; e++) {
+ channels = format[5 + e * 2];
+ type = format[6 + e * 2];
+
+ switch (type) {
+ /* IEC 60958 Conformant, currently handled as MBLA */
+ case 0x00:
+ /* Multi Bit Linear Audio (Raw) */
+ case 0x06:
+ formation->pcm += channels;
+ break;
+ /* MIDI Conformant */
+ case 0x0d:
+ formation->midi = channels;
+ break;
+ /* IEC 61937-3 to 7 */
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ /* Multi Bit Linear Audio */
+ case 0x07: /* DVD-Audio */
+ case 0x0c: /* High Precision */
+ /* One Bit Audio */
+ case 0x08: /* (Plain) Raw */
+ case 0x09: /* (Plain) SACD */
+ case 0x0a: /* (Encoded) Raw */
+ case 0x0b: /* (Encoded) SACD */
+ /* SMPTE Time-Code conformant */
+ case 0x0e:
+ /* Sample Count */
+ case 0x0f:
+ /* Anciliary Data */
+ case 0x10:
+ /* Synchronization Stream (Stereo Raw audio) */
+ case 0x40:
+ /* Don't care */
+ case 0xff:
+ default:
+ return -ENOSYS; /* not supported */
+ }
+ }
+
+ if (formation->pcm > AMDTP_MAX_CHANNELS_FOR_PCM ||
+ formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
+ return -ENOSYS;
+
+ return 0;
+}
+
+static int
+assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *buf, unsigned int *len,
+ u8 **formats)
+{
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, eid;
+ int err;
+
+ /* get format at current sampling rate */
+ err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get current stream format for isoc %s plug %d:%d\n",
+ (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+ pid, err);
+ goto end;
+ }
+
+ /* parse and set stream format */
+ eid = 0;
+ err = snd_oxfw_stream_parse_format(buf, &formation);
+ if (err < 0)
+ goto end;
+
+ formats[eid] = kmalloc(*len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ memcpy(formats[eid], buf, *len);
+
+ /* apply the format for each available sampling rate */
+ for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
+ if (formation.rate == oxfw_rate_table[i])
+ continue;
+
+ err = avc_general_inquiry_sig_fmt(oxfw->unit,
+ oxfw_rate_table[i],
+ dir, pid);
+ if (err < 0)
+ continue;
+
+ eid++;
+ formats[eid] = kmalloc(*len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ memcpy(formats[eid], buf, *len);
+ formats[eid][2] = avc_stream_rate_table[i];
+ }
+
+ err = 0;
+ oxfw->assumed = true;
+end:
+ return err;
+}
+
+static int fill_stream_formats(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ unsigned short pid)
+{
+ u8 *buf, **formats;
+ unsigned int len, eid = 0;
+ struct snd_oxfw_stream_formation dummy;
+ int err;
+
+ buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (dir == AVC_GENERAL_PLUG_DIR_OUT)
+ formats = oxfw->tx_stream_formats;
+ else
+ formats = oxfw->rx_stream_formats;
+
+ /* get first entry */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
+ if (err == -ENOSYS) {
+ /* LIST subfunction is not implemented */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = assume_stream_formats(oxfw, dir, pid, buf, &len,
+ formats);
+ goto end;
+ } else if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get stream format %d for isoc %s plug %d:%d\n",
+ eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+ pid, err);
+ goto end;
+ }
+
+ /* LIST subfunction is implemented */
+ while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
+ /* The format is too short. */
+ if (len < 3) {
+ err = -EIO;
+ break;
+ }
+
+ /* parse and set stream format */
+ err = snd_oxfw_stream_parse_format(buf, &dummy);
+ if (err < 0)
+ break;
+
+ formats[eid] = kmalloc(len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ break;
+ }
+ memcpy(formats[eid], buf, len);
+
+ /* get next entry */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = avc_stream_get_format_list(oxfw->unit, dir, 0,
+ buf, &len, ++eid);
+ /* No entries remained. */
+ if (err == -EINVAL) {
+ err = 0;
+ break;
+ } else if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get stream format %d for isoc %s plug %d:%d\n",
+ eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
+ "out",
+ pid, err);
+ break;
+ }
+ }
+end:
+ kfree(buf);
+ return err;
+}
+
+int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
+{
+ u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
+ int err;
+
+ /* the number of plugs for isoc in/out, ext in/out */
+ err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get info for isoc/external in/out plugs: %d\n",
+ err);
+ goto end;
+ } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
+ err = -ENOSYS;
+ goto end;
+ }
+
+ /* use oPCR[0] if exists */
+ if (plugs[1] > 0) {
+ err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
+ if (err < 0)
+ goto end;
+ oxfw->has_output = true;
+ }
+
+ /* use iPCR[0] if exists */
+ if (plugs[0] > 0)
+ err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
+end:
+ return err;
+}
+
+void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
+{
+ oxfw->dev_lock_changed = true;
+ wake_up(&oxfw->hwdep_wait);
+}
+
+int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ /* user land lock this */
+ if (oxfw->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto end;
+ }
+
+ /* this is the first time */
+ if (oxfw->dev_lock_count++ == 0)
+ snd_oxfw_stream_lock_changed(oxfw);
+ err = 0;
+end:
+ spin_unlock_irq(&oxfw->lock);
+ return err;
+}
+
+void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
+{
+ spin_lock_irq(&oxfw->lock);
+
+ if (WARN_ON(oxfw->dev_lock_count <= 0))
+ goto end;
+ if (--oxfw->dev_lock_count == 0)
+ snd_oxfw_stream_lock_changed(oxfw);
+end:
+ spin_unlock_irq(&oxfw->lock);
+}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
new file mode 100644
index 000000000000..60e5cad0531a
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw.c
@@ -0,0 +1,317 @@
+/*
+ * oxfw.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
+/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
+
+#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
+#define OXFORD_HARDWARE_ID_OXFW970 0x39443841
+#define OXFORD_HARDWARE_ID_OXFW971 0x39373100
+
+#define VENDOR_LOUD 0x000ff2
+#define VENDOR_GRIFFIN 0x001292
+#define VENDOR_BEHRINGER 0x001564
+#define VENDOR_LACIE 0x00d04b
+
+#define SPECIFIER_1394TA 0x00a02d
+#define VERSION_AVC 0x010001
+
+MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("snd-firewire-speakers");
+
+static bool detect_loud_models(struct fw_unit *unit)
+{
+ const char *const models[] = {
+ "Onyxi",
+ "Onyx-i",
+ "d.Pro",
+ "Mackie Onyx Satellite",
+ "Tapco LINK.firewire 4x6",
+ "U.420"};
+ char model[32];
+ unsigned int i;
+ int err;
+
+ err = fw_csr_string(unit->directory, CSR_MODEL,
+ model, sizeof(model));
+ if (err < 0)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(models); i++) {
+ if (strcmp(models[i], model) == 0)
+ break;
+ }
+
+ return (i < ARRAY_SIZE(models));
+}
+
+static int name_card(struct snd_oxfw *oxfw)
+{
+ struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
+ char vendor[24];
+ char model[32];
+ const char *d, *v, *m;
+ u32 firmware;
+ int err;
+
+ /* get vendor name from root directory */
+ err = fw_csr_string(fw_dev->config_rom + 5, CSR_VENDOR,
+ vendor, sizeof(vendor));
+ if (err < 0)
+ goto end;
+
+ /* get model name from unit directory */
+ err = fw_csr_string(oxfw->unit->directory, CSR_MODEL,
+ model, sizeof(model));
+ if (err < 0)
+ goto end;
+
+ err = snd_fw_transaction(oxfw->unit, TCODE_READ_QUADLET_REQUEST,
+ OXFORD_FIRMWARE_ID_ADDRESS, &firmware, 4, 0);
+ if (err < 0)
+ goto end;
+ be32_to_cpus(&firmware);
+
+ /* to apply card definitions */
+ if (oxfw->device_info) {
+ d = oxfw->device_info->driver_name;
+ v = oxfw->device_info->vendor_name;
+ m = oxfw->device_info->model_name;
+ } else {
+ d = "OXFW";
+ v = vendor;
+ m = model;
+ }
+
+ strcpy(oxfw->card->driver, d);
+ strcpy(oxfw->card->mixername, m);
+ strcpy(oxfw->card->shortname, m);
+
+ snprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
+ "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
+ v, m, firmware >> 20, firmware & 0xffff,
+ fw_dev->config_rom[3], fw_dev->config_rom[4],
+ dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
+end:
+ return err;
+}
+
+static void oxfw_card_free(struct snd_card *card)
+{
+ struct snd_oxfw *oxfw = card->private_data;
+ unsigned int i;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ kfree(oxfw->tx_stream_formats[i]);
+ kfree(oxfw->rx_stream_formats[i]);
+ }
+
+ mutex_destroy(&oxfw->mutex);
+}
+
+static int oxfw_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *id)
+{
+ struct snd_card *card;
+ struct snd_oxfw *oxfw;
+ int err;
+
+ if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit))
+ return -ENODEV;
+
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*oxfw), &card);
+ if (err < 0)
+ return err;
+
+ card->private_free = oxfw_card_free;
+ oxfw = card->private_data;
+ oxfw->card = card;
+ mutex_init(&oxfw->mutex);
+ oxfw->unit = unit;
+ oxfw->device_info = (const struct device_info *)id->driver_data;
+ spin_lock_init(&oxfw->lock);
+ init_waitqueue_head(&oxfw->hwdep_wait);
+
+ err = snd_oxfw_stream_discover(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = name_card(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_create_pcm(oxfw);
+ if (err < 0)
+ goto error;
+
+ if (oxfw->device_info) {
+ err = snd_oxfw_create_mixer(oxfw);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_oxfw_proc_init(oxfw);
+
+ err = snd_oxfw_create_midi(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_create_hwdep(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
+ if (err < 0)
+ goto error;
+ if (oxfw->has_output) {
+ err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+ goto error;
+ }
+ dev_set_drvdata(&unit->device, oxfw);
+
+ return 0;
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static void oxfw_bus_reset(struct fw_unit *unit)
+{
+ struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
+
+ fcp_bus_reset(oxfw->unit);
+
+ mutex_lock(&oxfw->mutex);
+
+ snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+}
+
+static void oxfw_remove(struct fw_unit *unit)
+{
+ struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
+
+ snd_card_disconnect(oxfw->card);
+
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+ snd_card_free_when_closed(oxfw->card);
+}
+
+static const struct device_info griffin_firewave = {
+ .driver_name = "FireWave",
+ .vendor_name = "Griffin",
+ .model_name = "FireWave",
+ .mixer_channels = 6,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x02,
+};
+
+static const struct device_info lacie_speakers = {
+ .driver_name = "FWSpeakers",
+ .vendor_name = "LaCie",
+ .model_name = "FireWire Speakers",
+ .mixer_channels = 1,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x01,
+};
+
+static const struct ieee1394_device_id oxfw_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_GRIFFIN,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&griffin_firewave,
+ },
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_LACIE,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&lacie_speakers,
+ },
+ /* Behringer,F-Control Audio 202 */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = VENDOR_BEHRINGER,
+ .model_id = 0x00fc22,
+ },
+ /*
+ * Any Mackie(Loud) models (name string/model id):
+ * Onyx-i series (former models): 0x081216
+ * Mackie Onyx Satellite: 0x00200f
+ * Tapco LINK.firewire 4x6: 0x000460
+ * d.2 pro: Unknown
+ * d.4 pro: Unknown
+ * U.420: Unknown
+ * U.420d: Unknown
+ */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_LOUD,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
+
+static struct fw_driver oxfw_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = oxfw_probe,
+ .update = oxfw_bus_reset,
+ .remove = oxfw_remove,
+ .id_table = oxfw_id_table,
+};
+
+static int __init snd_oxfw_init(void)
+{
+ return driver_register(&oxfw_driver.driver);
+}
+
+static void __exit snd_oxfw_exit(void)
+{
+ driver_unregister(&oxfw_driver.driver);
+}
+
+module_init(snd_oxfw_init);
+module_exit(snd_oxfw_exit);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
new file mode 100644
index 000000000000..cace5ad4fe76
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw.h
@@ -0,0 +1,146 @@
+/*
+ * oxfw.h - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/rawmidi.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+
+#include "../lib.h"
+#include "../fcp.h"
+#include "../packets-buffer.h"
+#include "../iso-resources.h"
+#include "../amdtp.h"
+#include "../cmp.h"
+
+struct device_info {
+ const char *driver_name;
+ const char *vendor_name;
+ const char *model_name;
+ unsigned int mixer_channels;
+ u8 mute_fb_id;
+ u8 volume_fb_id;
+};
+
+/* This is an arbitrary number for convinience. */
+#define SND_OXFW_STREAM_FORMAT_ENTRIES 10
+struct snd_oxfw {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ const struct device_info *device_info;
+ struct mutex mutex;
+ spinlock_t lock;
+
+ bool has_output;
+ u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
+ u8 *rx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
+ bool assumed;
+ struct cmp_connection out_conn;
+ struct cmp_connection in_conn;
+ struct amdtp_stream tx_stream;
+ struct amdtp_stream rx_stream;
+ unsigned int capture_substreams;
+ unsigned int playback_substreams;
+
+ unsigned int midi_input_ports;
+ unsigned int midi_output_ports;
+
+ bool mute;
+ s16 volume[6];
+ s16 volume_min;
+ s16 volume_max;
+
+ int dev_lock_count;
+ bool dev_lock_changed;
+ wait_queue_head_t hwdep_wait;
+};
+
+/*
+ * AV/C Stream Format Information Specification 1.1 Working Draft
+ * (Apr 2005, 1394TA)
+ */
+int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *format, unsigned int len);
+int avc_stream_get_format(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len, unsigned int eid);
+static inline int
+avc_stream_get_format_single(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len)
+{
+ return avc_stream_get_format(unit, dir, pid, buf, len, 0xff);
+}
+static inline int
+avc_stream_get_format_list(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len,
+ unsigned int eid)
+{
+ return avc_stream_get_format(unit, dir, pid, buf, len, eid);
+}
+
+/*
+ * AV/C Digital Interface Command Set General Specification 4.2
+ * (Sep 2004, 1394TA)
+ */
+int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
+ enum avc_general_plug_dir dir,
+ unsigned short pid);
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels);
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+
+struct snd_oxfw_stream_formation {
+ unsigned int rate;
+ unsigned int pcm;
+ unsigned int midi;
+};
+int snd_oxfw_stream_parse_format(u8 *format,
+ struct snd_oxfw_stream_formation *formation);
+int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ struct snd_oxfw_stream_formation *formation);
+
+int snd_oxfw_stream_discover(struct snd_oxfw *oxfw);
+
+void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_mixer(struct snd_oxfw *oxfw);
+
+void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
deleted file mode 100644
index 768d40ddfebb..000000000000
--- a/sound/firewire/speakers.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * OXFW970-based speakers driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include "cmp.h"
-#include "fcp.h"
-#include "amdtp.h"
-#include "lib.h"
-
-#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
-/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
-
-#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
-#define OXFORD_HARDWARE_ID_OXFW970 0x39443841
-#define OXFORD_HARDWARE_ID_OXFW971 0x39373100
-
-#define VENDOR_GRIFFIN 0x001292
-#define VENDOR_LACIE 0x00d04b
-
-#define SPECIFIER_1394TA 0x00a02d
-#define VERSION_AVC 0x010001
-
-struct device_info {
- const char *driver_name;
- const char *short_name;
- const char *long_name;
- int (*pcm_constraints)(struct snd_pcm_runtime *runtime);
- unsigned int mixer_channels;
- u8 mute_fb_id;
- u8 volume_fb_id;
-};
-
-struct fwspk {
- struct snd_card *card;
- struct fw_unit *unit;
- const struct device_info *device_info;
- struct mutex mutex;
- struct cmp_connection connection;
- struct amdtp_stream stream;
- bool mute;
- s16 volume[6];
- s16 volume_min;
- s16 volume_max;
-};
-
-MODULE_DESCRIPTION("FireWire speakers driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- static unsigned int stereo_rates[] = { 48000, 96000 };
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-
- /* two channels work only at 48/96 kHz */
- if (snd_interval_max(channels) < 6)
- return snd_interval_list(rate, 2, stereo_rates, 0);
- return 0;
-}
-
-static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- static const struct snd_interval all_channels = { .min = 6, .max = 6 };
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /* 32/44.1 kHz work only with all six channels */
- if (snd_interval_max(rate) < 48000)
- return snd_interval_refine(channels, &all_channels);
- return 0;
-}
-
-static int firewave_constraints(struct snd_pcm_runtime *runtime)
-{
- static unsigned int channels_list[] = { 2, 6 };
- static struct snd_pcm_hw_constraint_list channels_list_constraint = {
- .count = 2,
- .list = channels_list,
- };
- int err;
-
- runtime->hw.rates = SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_96000;
- runtime->hw.channels_max = 6;
-
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &channels_list_constraint);
- if (err < 0)
- return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- firewave_rate_constraint, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- if (err < 0)
- return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- firewave_channels_constraint, NULL,
- SNDRV_PCM_HW_PARAM_RATE, -1);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
-{
- runtime->hw.rates = SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000;
-
- return 0;
-}
-
-static int fwspk_open(struct snd_pcm_substream *substream)
-{
- static const struct snd_pcm_hardware hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = AMDTP_OUT_PCM_FORMAT_BITS,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 4 * 1024 * 1024,
- .period_bytes_min = 1,
- .period_bytes_max = UINT_MAX,
- .periods_min = 1,
- .periods_max = UINT_MAX,
- };
- struct fwspk *fwspk = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- runtime->hw = hardware;
-
- err = fwspk->device_info->pcm_constraints(runtime);
- if (err < 0)
- return err;
- err = snd_pcm_limit_hw_rates(runtime);
- if (err < 0)
- return err;
-
- err = amdtp_stream_add_pcm_hw_constraints(&fwspk->stream, runtime);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int fwspk_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-static void fwspk_stop_stream(struct fwspk *fwspk)
-{
- if (amdtp_stream_running(&fwspk->stream)) {
- amdtp_stream_stop(&fwspk->stream);
- cmp_connection_break(&fwspk->connection);
- }
-}
-
-static int fwspk_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct fwspk *fwspk = substream->private_data;
- int err;
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- goto error;
-
- amdtp_stream_set_parameters(&fwspk->stream,
- params_rate(hw_params),
- params_channels(hw_params),
- 0);
-
- amdtp_stream_set_pcm_format(&fwspk->stream,
- params_format(hw_params));
-
- err = avc_general_set_sig_fmt(fwspk->unit, params_rate(hw_params),
- AVC_GENERAL_PLUG_DIR_IN, 0);
- if (err < 0) {
- dev_err(&fwspk->unit->device, "failed to set sample rate\n");
- goto err_buffer;
- }
-
- return 0;
-
-err_buffer:
- snd_pcm_lib_free_vmalloc_buffer(substream);
-error:
- return err;
-}
-
-static int fwspk_hw_free(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int fwspk_prepare(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
- int err;
-
- mutex_lock(&fwspk->mutex);
-
- if (amdtp_streaming_error(&fwspk->stream))
- fwspk_stop_stream(fwspk);
-
- if (!amdtp_stream_running(&fwspk->stream)) {
- err = cmp_connection_establish(&fwspk->connection,
- amdtp_stream_get_max_payload(&fwspk->stream));
- if (err < 0)
- goto err_mutex;
-
- err = amdtp_stream_start(&fwspk->stream,
- fwspk->connection.resources.channel,
- fwspk->connection.speed);
- if (err < 0)
- goto err_connection;
- }
-
- mutex_unlock(&fwspk->mutex);
-
- amdtp_stream_pcm_prepare(&fwspk->stream);
-
- return 0;
-
-err_connection:
- cmp_connection_break(&fwspk->connection);
-err_mutex:
- mutex_unlock(&fwspk->mutex);
-
- return err;
-}
-
-static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct fwspk *fwspk = substream->private_data;
- struct snd_pcm_substream *pcm;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- pcm = substream;
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pcm = NULL;
- break;
- default:
- return -EINVAL;
- }
- amdtp_stream_pcm_trigger(&fwspk->stream, pcm);
- return 0;
-}
-
-static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
-
- return amdtp_stream_pcm_pointer(&fwspk->stream);
-}
-
-static int fwspk_create_pcm(struct fwspk *fwspk)
-{
- static struct snd_pcm_ops ops = {
- .open = fwspk_open,
- .close = fwspk_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = fwspk_hw_params,
- .hw_free = fwspk_hw_free,
- .prepare = fwspk_prepare,
- .trigger = fwspk_trigger,
- .pointer = fwspk_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
- };
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = fwspk;
- strcpy(pcm->name, fwspk->device_info->short_name);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
- return 0;
-}
-
-enum control_action { CTL_READ, CTL_WRITE };
-enum control_attribute {
- CTL_MIN = 0x02,
- CTL_MAX = 0x03,
- CTL_CURRENT = 0x10,
-};
-
-static int fwspk_mute_command(struct fwspk *fwspk, bool *value,
- enum control_action action)
-{
- u8 *buf;
- u8 response_ok;
- int err;
-
- buf = kmalloc(11, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (action == CTL_READ) {
- buf[0] = 0x01; /* AV/C, STATUS */
- response_ok = 0x0c; /* STABLE */
- } else {
- buf[0] = 0x00; /* AV/C, CONTROL */
- response_ok = 0x09; /* ACCEPTED */
- }
- buf[1] = 0x08; /* audio unit 0 */
- buf[2] = 0xb8; /* FUNCTION BLOCK */
- buf[3] = 0x81; /* function block type: feature */
- buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */
- buf[5] = 0x10; /* control attribute: current */
- buf[6] = 0x02; /* selector length */
- buf[7] = 0x00; /* audio channel number */
- buf[8] = 0x01; /* control selector: mute */
- buf[9] = 0x01; /* control data length */
- if (action == CTL_READ)
- buf[10] = 0xff;
- else
- buf[10] = *value ? 0x70 : 0x60;
-
- err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe);
- if (err < 0)
- goto error;
- if (err < 11) {
- dev_err(&fwspk->unit->device, "short FCP response\n");
- err = -EIO;
- goto error;
- }
- if (buf[0] != response_ok) {
- dev_err(&fwspk->unit->device, "mute command failed\n");
- err = -EIO;
- goto error;
- }
- if (action == CTL_READ)
- *value = buf[10] == 0x70;
-
- err = 0;
-
-error:
- kfree(buf);
-
- return err;
-}
-
-static int fwspk_volume_command(struct fwspk *fwspk, s16 *value,
- unsigned int channel,
- enum control_attribute attribute,
- enum control_action action)
-{
- u8 *buf;
- u8 response_ok;
- int err;
-
- buf = kmalloc(12, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (action == CTL_READ) {
- buf[0] = 0x01; /* AV/C, STATUS */
- response_ok = 0x0c; /* STABLE */
- } else {
- buf[0] = 0x00; /* AV/C, CONTROL */
- response_ok = 0x09; /* ACCEPTED */
- }
- buf[1] = 0x08; /* audio unit 0 */
- buf[2] = 0xb8; /* FUNCTION BLOCK */
- buf[3] = 0x81; /* function block type: feature */
- buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */
- buf[5] = attribute; /* control attribute */
- buf[6] = 0x02; /* selector length */
- buf[7] = channel; /* audio channel number */
- buf[8] = 0x02; /* control selector: volume */
- buf[9] = 0x02; /* control data length */
- if (action == CTL_READ) {
- buf[10] = 0xff;
- buf[11] = 0xff;
- } else {
- buf[10] = *value >> 8;
- buf[11] = *value;
- }
-
- err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe);
- if (err < 0)
- goto error;
- if (err < 12) {
- dev_err(&fwspk->unit->device, "short FCP response\n");
- err = -EIO;
- goto error;
- }
- if (buf[0] != response_ok) {
- dev_err(&fwspk->unit->device, "volume command failed\n");
- err = -EIO;
- goto error;
- }
- if (action == CTL_READ)
- *value = (buf[10] << 8) | buf[11];
-
- err = 0;
-
-error:
- kfree(buf);
-
- return err;
-}
-
-static int fwspk_mute_get(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
-
- value->value.integer.value[0] = !fwspk->mute;
-
- return 0;
-}
-
-static int fwspk_mute_put(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- bool mute;
- int err;
-
- mute = !value->value.integer.value[0];
-
- if (mute == fwspk->mute)
- return 0;
-
- err = fwspk_mute_command(fwspk, &mute, CTL_WRITE);
- if (err < 0)
- return err;
- fwspk->mute = mute;
-
- return 1;
-}
-
-static int fwspk_volume_info(struct snd_kcontrol *control,
- struct snd_ctl_elem_info *info)
-{
- struct fwspk *fwspk = control->private_data;
-
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = fwspk->device_info->mixer_channels;
- info->value.integer.min = fwspk->volume_min;
- info->value.integer.max = fwspk->volume_max;
-
- return 0;
-}
-
-static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
-
-static int fwspk_volume_get(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- unsigned int i;
-
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
- value->value.integer.value[channel_map[i]] = fwspk->volume[i];
-
- return 0;
-}
-
-static int fwspk_volume_put(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- unsigned int i, changed_channels;
- bool equal_values = true;
- s16 volume;
- int err;
-
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
- if (value->value.integer.value[i] < fwspk->volume_min ||
- value->value.integer.value[i] > fwspk->volume_max)
- return -EINVAL;
- if (value->value.integer.value[i] !=
- value->value.integer.value[0])
- equal_values = false;
- }
-
- changed_channels = 0;
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
- if (value->value.integer.value[channel_map[i]] !=
- fwspk->volume[i])
- changed_channels |= 1 << (i + 1);
-
- if (equal_values && changed_channels != 0)
- changed_channels = 1 << 0;
-
- for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) {
- volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
- if (changed_channels & (1 << i)) {
- err = fwspk_volume_command(fwspk, &volume, i,
- CTL_CURRENT, CTL_WRITE);
- if (err < 0)
- return err;
- }
- if (i > 0)
- fwspk->volume[i - 1] = volume;
- }
-
- return changed_channels != 0;
-}
-
-static int fwspk_create_mixer(struct fwspk *fwspk)
-{
- static const struct snd_kcontrol_new controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = fwspk_mute_get,
- .put = fwspk_mute_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Volume",
- .info = fwspk_volume_info,
- .get = fwspk_volume_get,
- .put = fwspk_volume_put,
- },
- };
- unsigned int i, first_ch;
- int err;
-
- err = fwspk_volume_command(fwspk, &fwspk->volume_min,
- 0, CTL_MIN, CTL_READ);
- if (err < 0)
- return err;
- err = fwspk_volume_command(fwspk, &fwspk->volume_max,
- 0, CTL_MAX, CTL_READ);
- if (err < 0)
- return err;
-
- err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ);
- if (err < 0)
- return err;
-
- first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1;
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
- err = fwspk_volume_command(fwspk, &fwspk->volume[i],
- first_ch + i, CTL_CURRENT, CTL_READ);
- if (err < 0)
- return err;
- }
-
- for (i = 0; i < ARRAY_SIZE(controls); ++i) {
- err = snd_ctl_add(fwspk->card,
- snd_ctl_new1(&controls[i], fwspk));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static u32 fwspk_read_firmware_version(struct fw_unit *unit)
-{
- __be32 data;
- int err;
-
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0);
- return err >= 0 ? be32_to_cpu(data) : 0;
-}
-
-static void fwspk_card_free(struct snd_card *card)
-{
- struct fwspk *fwspk = card->private_data;
-
- amdtp_stream_destroy(&fwspk->stream);
- cmp_connection_destroy(&fwspk->connection);
- fw_unit_put(fwspk->unit);
- mutex_destroy(&fwspk->mutex);
-}
-
-static int fwspk_probe(struct fw_unit *unit,
- const struct ieee1394_device_id *id)
-{
- struct fw_device *fw_dev = fw_parent_device(unit);
- struct snd_card *card;
- struct fwspk *fwspk;
- u32 firmware;
- int err;
-
- err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
- sizeof(*fwspk), &card);
- if (err < 0)
- return err;
-
- fwspk = card->private_data;
- fwspk->card = card;
- mutex_init(&fwspk->mutex);
- fwspk->unit = fw_unit_get(unit);
- fwspk->device_info = (const struct device_info *)id->driver_data;
-
- err = cmp_connection_init(&fwspk->connection, unit, CMP_INPUT, 0);
- if (err < 0)
- goto err_unit;
-
- err = amdtp_stream_init(&fwspk->stream, unit, AMDTP_OUT_STREAM,
- CIP_NONBLOCKING);
- if (err < 0)
- goto err_connection;
-
- card->private_free = fwspk_card_free;
-
- strcpy(card->driver, fwspk->device_info->driver_name);
- strcpy(card->shortname, fwspk->device_info->short_name);
- firmware = fwspk_read_firmware_version(unit);
- snprintf(card->longname, sizeof(card->longname),
- "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
- fwspk->device_info->long_name,
- firmware >> 20, firmware & 0xffff,
- fw_dev->config_rom[3], fw_dev->config_rom[4],
- dev_name(&unit->device), 100 << fw_dev->max_speed);
- strcpy(card->mixername, "OXFW970");
-
- err = fwspk_create_pcm(fwspk);
- if (err < 0)
- goto error;
-
- err = fwspk_create_mixer(fwspk);
- if (err < 0)
- goto error;
-
- err = snd_card_register(card);
- if (err < 0)
- goto error;
-
- dev_set_drvdata(&unit->device, fwspk);
-
- return 0;
-
-err_connection:
- cmp_connection_destroy(&fwspk->connection);
-err_unit:
- fw_unit_put(fwspk->unit);
- mutex_destroy(&fwspk->mutex);
-error:
- snd_card_free(card);
- return err;
-}
-
-static void fwspk_bus_reset(struct fw_unit *unit)
-{
- struct fwspk *fwspk = dev_get_drvdata(&unit->device);
-
- fcp_bus_reset(fwspk->unit);
-
- if (cmp_connection_update(&fwspk->connection) < 0) {
- amdtp_stream_pcm_abort(&fwspk->stream);
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
- return;
- }
-
- amdtp_stream_update(&fwspk->stream);
-}
-
-static void fwspk_remove(struct fw_unit *unit)
-{
- struct fwspk *fwspk = dev_get_drvdata(&unit->device);
-
- amdtp_stream_pcm_abort(&fwspk->stream);
- snd_card_disconnect(fwspk->card);
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- snd_card_free_when_closed(fwspk->card);
-}
-
-static const struct device_info griffin_firewave = {
- .driver_name = "FireWave",
- .short_name = "FireWave",
- .long_name = "Griffin FireWave Surround",
- .pcm_constraints = firewave_constraints,
- .mixer_channels = 6,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x02,
-};
-
-static const struct device_info lacie_speakers = {
- .driver_name = "FWSpeakers",
- .short_name = "FireWire Speakers",
- .long_name = "LaCie FireWire Speakers",
- .pcm_constraints = lacie_speakers_constraints,
- .mixer_channels = 1,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x01,
-};
-
-static const struct ieee1394_device_id fwspk_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID |
- IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION,
- .vendor_id = VENDOR_GRIFFIN,
- .model_id = 0x00f970,
- .specifier_id = SPECIFIER_1394TA,
- .version = VERSION_AVC,
- .driver_data = (kernel_ulong_t)&griffin_firewave,
- },
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID |
- IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION,
- .vendor_id = VENDOR_LACIE,
- .model_id = 0x00f970,
- .specifier_id = SPECIFIER_1394TA,
- .version = VERSION_AVC,
- .driver_data = (kernel_ulong_t)&lacie_speakers,
- },
- { }
-};
-MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table);
-
-static struct fw_driver fwspk_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = KBUILD_MODNAME,
- .bus = &fw_bus_type,
- },
- .probe = fwspk_probe,
- .update = fwspk_bus_reset,
- .remove = fwspk_remove,
- .id_table = fwspk_id_table,
-};
-
-static int __init alsa_fwspk_init(void)
-{
- return driver_register(&fwspk_driver.driver);
-}
-
-static void __exit alsa_fwspk_exit(void)
-{
- driver_unregister(&fwspk_driver.driver);
-}
-
-module_init(alsa_fwspk_init);
-module_exit(alsa_fwspk_exit);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index f3735e64791c..67dbfde837ab 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -465,17 +465,10 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"44.1kHz", "Off", "48kHz", "32kHz",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= 4)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
@@ -570,22 +563,13 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
- const char **input_names;
- unsigned int num_names, idx;
+ unsigned int num_names;
num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
if (!num_names)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_names;
- idx = uinfo->value.enumerated.item;
- if (idx >= num_names)
- return -EINVAL;
- input_names = ak->adc_info[mixer_ch].input_names;
- strlcpy(uinfo->value.enumerated.name, input_names[idx],
- sizeof(uinfo->value.enumerated.name));
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_names,
+ ak->adc_info[mixer_ch].input_names);
}
static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index f0fd98e695e3..01a07986f4a3 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -731,18 +731,12 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
static int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"Line", "Mix", "CD", "Synth", "Video",
"Mic", "Phone",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item > 6)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 7, texts);
}
static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index b3b4f15e45ba..b5450143407b 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -614,8 +614,7 @@ static int snd_es1688_free(struct snd_es1688 *chip)
{
if (chip->hardware != ES1688_HW_UNDEF)
snd_es1688_init(chip, 0);
- if (chip->res_port)
- release_and_free_resource(chip->res_port);
+ release_and_free_resource(chip->res_port);
if (chip->irq >= 0)
free_irq(chip->irq, (void *) chip);
if (chip->dma8 >= 0) {
@@ -762,18 +761,12 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
static int snd_es1688_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[9] = {
+ static const char * const texts[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 6faaac60161a..b481bb8c31bc 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -156,6 +156,7 @@ struct snd_es18xx {
#define ES18XX_I2S 0x0200 /* I2S mixer control */
#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
#define ES18XX_CONTROL 0x0800 /* Has control ports */
+#define ES18XX_GPO_2BIT 0x1000 /* GPO0,1 controlled by PM port */
/* Power Management */
#define ES18XX_PM 0x07
@@ -964,44 +965,28 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts5Source[5] = {
+ static const char * const texts5Source[5] = {
"Mic", "CD", "Line", "Master", "Mix"
};
- static char *texts8Source[8] = {
+ static const char * const texts8Source[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (chip->version) {
case 0x1868:
case 0x1878:
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts5Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts5Source);
case 0x1887:
case 0x1888:
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts5Source);
case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
case 0x1879:
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts8Source);
default:
return -EINVAL;
}
- return 0;
}
static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1136,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
return snd_es18xx_read(chip, reg);
}
-#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \
+#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_es18xx_info_single, \
.get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \
- .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+ .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) }
+
+#define ES18XX_FL_INVERT (1 << 0)
+#define ES18XX_FL_PMPORT (1 << 1)
static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -1159,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+ int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
int val;
-
- val = snd_es18xx_reg_read(chip, reg);
+
+ if (pm_port)
+ val = inb(chip->port + ES18XX_PM);
+ else
+ val = snd_es18xx_reg_read(chip, reg);
ucontrol->value.integer.value[0] = (val >> shift) & mask;
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
@@ -1175,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+ int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
unsigned char val;
val = (ucontrol->value.integer.value[0] & mask);
@@ -1183,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
val = mask - val;
mask <<= shift;
val <<= shift;
+ if (pm_port) {
+ unsigned char cur = inb(chip->port + ES18XX_PM);
+
+ if ((cur & mask) == val)
+ return 0;
+ outb((cur & ~mask) | val, chip->port + ES18XX_PM);
+ return 1;
+ }
+
return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
}
@@ -1304,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT),
ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
@@ -1363,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
};
+static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = {
+ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT),
+ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT),
+};
+
static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
{
int data;
@@ -1629,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
switch (chip->version) {
case 0x1868:
- chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
+ chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT;
break;
case 0x1869:
- chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
+ chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT;
break;
case 0x1878:
chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
@@ -1642,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
break;
case 0x1887:
case 0x1888:
- chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
+ chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
break;
default:
snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1944,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
return err;
}
}
+ if (chip->caps & ES18XX_GPO_2BIT) {
+ for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
index 031dc69b7470..17e49a071af4 100644
--- a/sound/isa/msnd/msnd_pinnacle_mixer.c
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -55,20 +55,13 @@
static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Analog", "MASS", "SPDIF",
};
struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = items;
- if (uinfo->value.enumerated.item >= items)
- uinfo->value.enumerated.item = items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, items, texts);
}
static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 4e3fcfb15ad4..95b39beb61c1 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -105,8 +105,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
snd_device_free(dev->card, hw->pcm);
if (hw->emu)
snd_emux_free(hw->emu);
- if (hw->memhdr)
- snd_util_memhdr_free(hw->memhdr);
+ snd_util_memhdr_free(hw->memhdr);
hw->emu = NULL;
hw->memhdr = NULL;
return 0;
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 0bbcd4714d28..72b10f4f3e70 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -702,17 +702,11 @@ static int snd_sb16_get_dma_mode(struct snd_sb *chip)
static int snd_sb16_dma_control_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Auto", "Playback", "Capture"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_sb16_dma_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 3ef990602cdd..f22b4480828e 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -184,8 +184,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
static int snd_sbdsp_free(struct snd_sb *chip)
{
- if (chip->res_port)
- release_and_free_resource(chip->res_port);
+ release_and_free_resource(chip->res_port);
if (chip->irq >= 0)
free_irq(chip->irq, (void *) chip);
#ifdef CONFIG_ISA
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 1ff78ec9f0ac..e403334a19ad 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -182,17 +182,11 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[5] = {
+ static const char * const texts[5] = {
"CD", "Mic", "Line", "Synth", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -275,18 +269,11 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"L chan only", "R chan only", "L ch/2 + R ch/2"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
@@ -335,17 +322,11 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"Mic", "CD", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 360b08b03e1d..347bb1bda110 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -1993,25 +1993,20 @@ EXPORT_SYMBOL(snd_wss_timer);
static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Line", "Aux", "Mic", "Mix"
};
- static char *opl3sa_texts[4] = {
+ static const char * const opl3sa_texts[4] = {
"Line", "CD", "Mic", "Mix"
};
- static char *gusmax_texts[4] = {
+ static const char * const gusmax_texts[4] = {
"Line", "Synth", "Mic", "Mix"
};
- char **ptexts = texts;
+ const char * const *ptexts = texts;
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
if (snd_BUG_ON(!chip->card))
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
if (!strcmp(chip->card->driver, "GUS MAX"))
ptexts = gusmax_texts;
switch (chip->hardware) {
@@ -2023,8 +2018,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
ptexts = opl3sa_texts;
break;
}
- strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 4, ptexts);
}
static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index 04bb06c03ec8..33b08fcc27a9 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -201,17 +201,10 @@ static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol,
static int sgio2audio_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"Cam Mic", "Mic", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= 3)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int sgio2audio_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
index 279bc565ac7e..dae4d4344407 100644
--- a/sound/oss/uart401.c
+++ b/sound/oss/uart401.c
@@ -412,13 +412,10 @@ void unload_uart401(struct address_info *hw_config)
if (!devc->share_irq)
free_irq(devc->irq, devc);
- if (devc)
- {
- kfree(midi_devs[devc->my_dev]->converter);
- kfree(midi_devs[devc->my_dev]);
- kfree(devc);
- devc = NULL;
- }
+ kfree(midi_devs[devc->my_dev]->converter);
+ kfree(midi_devs[devc->my_dev]);
+ kfree(devc);
+
/* This kills midi_devs[x] */
sound_unload_mididev(hw_config->slots[4]);
}
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 4b20be79c1dd..29604a239c44 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -776,15 +776,9 @@ static int
snd_harmony_captureroute_info(struct snd_kcontrol *kc,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Line", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[2] = { "Line", "Mic" };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 14ad54b7928c..5ee2f17c287c 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -463,14 +463,8 @@ static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol,
{
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
- uinfo->value.enumerated.items = e->mask;
-
- if (uinfo->value.enumerated.item > e->mask - 1)
- uinfo->value.enumerated.item = e->mask - 1;
- strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2,
+ e->mask, e->texts);
}
static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 991762215417..ceaac1c41906 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -33,7 +33,8 @@
static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
const char *name);
static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
- const unsigned int *tlv, const char **slaves);
+ const unsigned int *tlv,
+ const char * const *slaves);
/*
* Chip specific initialization
@@ -81,22 +82,11 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi
/*
* shared line-in/mic controls
*/
-static int ac97_enum_text_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo,
- const char **texts, unsigned int nums)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = nums;
- if (uinfo->value.enumerated.item > nums - 1)
- uinfo->value.enumerated.item = nums - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
static int ac97_surround_jack_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[] = { "Shared", "Independent" };
- return ac97_enum_text_info(kcontrol, uinfo, texts, 2);
+ static const char * const texts[] = { "Shared", "Independent" };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int ac97_surround_jack_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -123,9 +113,9 @@ static int ac97_surround_jack_mode_put(struct snd_kcontrol *kcontrol, struct snd
static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[] = { "2ch", "4ch", "6ch", "8ch" };
- return ac97_enum_text_info(kcontrol, uinfo, texts,
- kcontrol->private_value);
+ static const char * const texts[] = { "2ch", "4ch", "6ch", "8ch" };
+
+ return snd_ctl_enum_info(uinfo, 1, kcontrol->private_value, texts);
}
static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -240,17 +230,11 @@ static inline int alc850_is_aux_back_surround(struct snd_ac97 *ac97)
static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Standard", "Small", "Smaller"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol,
@@ -293,15 +277,9 @@ static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker =
static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "AC-Link", "A/D Converter" };
+ static const char * const texts[2] = { "AC-Link", "A/D Converter" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol,
@@ -401,15 +379,9 @@ static int patch_yamaha_ymf743(struct snd_ac97 *ac97)
There is also a bit to mute S/PDIF output in a vendor-specific register. */
static int snd_ac97_ymf753_spdif_output_pin_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" };
+ static const char * const texts[3] = { "Disabled", "Pin 43", "Pin 48" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ymf753_spdif_output_pin_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1103,16 +1075,11 @@ static int patch_sigmatel_stac9756(struct snd_ac97 * ac97)
static int snd_ac97_stac9758_output_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = { "Input/Disabled", "Front Output",
+ static const char * const texts[5] = {
+ "Input/Disabled", "Front Output",
"Rear Output", "Center/LFE Output", "Mixer Output" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_ac97_stac9758_output_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1147,16 +1114,11 @@ static int snd_ac97_stac9758_output_jack_put(struct snd_kcontrol *kcontrol, stru
static int snd_ac97_stac9758_input_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[7] = { "Mic2 Jack", "Mic1 Jack", "Line In Jack",
+ static const char * const texts[7] = {
+ "Mic2 Jack", "Mic1 Jack", "Line In Jack",
"Front Jack", "Rear Jack", "Center/LFE Jack", "Mute" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item > 6)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 7, texts);
}
static int snd_ac97_stac9758_input_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1181,15 +1143,11 @@ static int snd_ac97_stac9758_input_jack_put(struct snd_kcontrol *kcontrol, struc
static int snd_ac97_stac9758_phonesel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "None", "Front Jack", "Rear Jack" };
+ static const char * const texts[3] = {
+ "None", "Front Jack", "Rear Jack"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_stac9758_phonesel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1804,15 +1762,9 @@ static int patch_ad1886(struct snd_ac97 * ac97)
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "AC-Link", "A/D Converter" };
+ static const char * const texts[2] = { "AC-Link", "A/D Converter" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_ad198x_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1994,15 +1946,9 @@ static int snd_ac97_ad1888_lohpsel_put(struct snd_kcontrol *kcontrol, struct snd
static int snd_ac97_ad1888_downmix_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"};
+ static const char * const texts[3] = {"Off", "6 -> 4", "6 -> 2"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ad1888_downmix_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2153,16 +2099,11 @@ static int patch_ad1980(struct snd_ac97 * ac97)
static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
+ static const char * const texts[4] = {
+ "High-Z", "3.7 V", "2.25 V", "0 V"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
@@ -2756,20 +2697,18 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc655[] = {
static int alc655_iec958_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" };
- static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" };
+ static const char * const texts_655[3] = {
+ "PCM", "Analog In", "IEC958 In"
+ };
+ static const char * const texts_658[4] = {
+ "PCM", "Analog1 In", "Analog2 In", "IEC958 In"
+ };
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- ac97->spec.dev_flags ?
- texts_658[uinfo->value.enumerated.item] :
- texts_655[uinfo->value.enumerated.item]);
- return 0;
+ if (ac97->spec.dev_flags)
+ return snd_ctl_enum_info(uinfo, 1, 4, texts_658);
+ else
+ return snd_ctl_enum_info(uinfo, 1, 3, texts_655);
}
static int alc655_iec958_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3055,15 +2994,9 @@ static int patch_cm9738(struct snd_ac97 * ac97)
static int snd_ac97_cmedia_spdif_playback_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Analog", "Digital" };
+ static const char * const texts[] = { "Analog", "Digital" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_cmedia_spdif_playback_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3235,15 +3168,9 @@ static const struct snd_kcontrol_new snd_ac97_cm9761_controls[] = {
static int cm9761_spdif_out_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" };
+ static const char * const texts[] = { "AC-Link", "ADC", "SPDIF-In" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int cm9761_spdif_out_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3270,7 +3197,9 @@ static int cm9761_spdif_out_source_put(struct snd_kcontrol *kcontrol, struct snd
ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0);
}
-static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" };
+static const char * const cm9761_dac_clock[] = {
+ "AC-Link", "SPDIF-In", "Both"
+};
static const struct ac97_enum cm9761_dac_clock_enum =
AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock);
@@ -3384,7 +3313,9 @@ static int patch_cm9761(struct snd_ac97 *ac97)
#define AC97_CM9780_MULTI_CHAN 0x66
#define AC97_CM9780_SPDIF 0x6c
-static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" };
+static const char * const cm9780_ch_select[] = {
+ "Front", "Side", "Center/LFE", "Rear"
+};
static const struct ac97_enum cm9780_ch_select_enum =
AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select);
static const struct snd_kcontrol_new cm9780_controls[] = {
@@ -3430,7 +3361,7 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),
AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),
};
-static const char *slave_vols_vt1616[] = {
+static const char * const slave_vols_vt1616[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -3438,7 +3369,7 @@ static const char *slave_vols_vt1616[] = {
NULL
};
-static const char *slave_sws_vt1616[] = {
+static const char * const slave_sws_vt1616[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -3459,10 +3390,11 @@ static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
/* create a virtual master control and add slaves */
static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
- const unsigned int *tlv, const char **slaves)
+ const unsigned int *tlv,
+ const char * const *slaves)
{
struct snd_kcontrol *kctl;
- const char **s;
+ const char * const *s;
int err;
kctl = snd_ctl_make_virtual_master(name, tlv);
@@ -3552,11 +3484,12 @@ static int snd_ac97_vt1617a_smart51_info(struct snd_kcontrol *kcontrol,
* is SM51EN *AND* it's Bit14, not Bit15 so the table is very
* counter-intuitive */
- static const char* texts[] = { "LineIn Mic1", "LineIn Mic1 Mic3",
+ static const char * const texts[] = {"LineIn Mic1", "LineIn Mic1 Mic3",
"Surr LFE/C Mic3", "LineIn LFE/C Mic3",
"LineIn Mic2", "LineIn Mic2 Mic1",
"Surr LFE Mic1", "Surr LFE Mic1 Mic2"};
- return ac97_enum_text_info(kcontrol, uinfo, texts, 8);
+
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol,
@@ -3685,7 +3618,7 @@ static int patch_vt1617a(struct snd_ac97 * ac97)
struct vt1618_uaj_item {
unsigned short mask;
unsigned short shift;
- const char *items[4];
+ const char * const items[4];
};
/* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */
@@ -3720,9 +3653,8 @@ static struct vt1618_uaj_item vt1618_uaj[3] = {
static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- return ac97_enum_text_info(kcontrol, uinfo,
- vt1618_uaj[kcontrol->private_value].items,
- 4);
+ return snd_ctl_enum_info(uinfo, 1, 4,
+ vt1618_uaj[kcontrol->private_value].items);
}
/* All of the vt1618 Universal Audio Jack twiddlers are on
@@ -3767,9 +3699,9 @@ static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol,
static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *txt_aux[] = {"Aux In", "Back Surr Out"};
+ static const char * const txt_aux[] = {"Aux In", "Back Surr Out"};
- return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2);
+ return snd_ctl_enum_info(uinfo, 1, 2, txt_aux);
}
static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 47bf8dfe8276..d1ce151fe722 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -49,7 +49,7 @@ struct ac97_enum {
unsigned char shift_l;
unsigned char shift_r;
unsigned short mask;
- const char **texts;
+ const char * const *texts;
};
#define AC97_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 5017176bfaa1..e9273fb2a505 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1,6 +1,6 @@
/*
* Asihpi soundcard
- * Copyright (c) by AudioScience Inc <alsa@audioscience.com>
+ * Copyright (c) by AudioScience Inc <support@audioscience.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,7 +28,6 @@
#include "hpioctl.h"
#include "hpicmn.h"
-
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@@ -47,7 +46,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
-MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx "
+MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx "
HPI_VER_STRING);
#if defined CONFIG_SND_DEBUG_VERBOSE
@@ -87,11 +86,11 @@ MODULE_PARM_DESC(enable_hpi_hwdep,
#ifdef KERNEL_ALSA_BUILD
static char *build_info = "Built using headers from kernel source";
module_param(build_info, charp, S_IRUGO);
-MODULE_PARM_DESC(build_info, "built using headers from kernel source");
+MODULE_PARM_DESC(build_info, "Built using headers from kernel source");
#else
static char *build_info = "Built within ALSA source";
module_param(build_info, charp, S_IRUGO);
-MODULE_PARM_DESC(build_info, "built within ALSA source");
+MODULE_PARM_DESC(build_info, "Built within ALSA source");
#endif
/* set to 1 to dump every control from adapter to log */
@@ -110,7 +109,7 @@ static int adapter_fs = DEFAULT_SAMPLERATE;
struct clk_source {
int source;
int index;
- char *name;
+ const char *name;
};
struct clk_cache {
@@ -125,6 +124,16 @@ struct snd_card_asihpi {
struct pci_dev *pci;
struct hpi_adapter *hpi;
+ /* In low latency mode there is only one stream, a pointer to its
+ * private data is stored here on trigger and cleared on stop.
+ * The interrupt handler uses it as a parameter when calling
+ * snd_card_asihpi_timer_function().
+ */
+ struct snd_card_asihpi_pcm *llmode_streampriv;
+ struct tasklet_struct t;
+ void (*pcm_start)(struct snd_pcm_substream *substream);
+ void (*pcm_stop)(struct snd_pcm_substream *substream);
+
u32 h_mixer;
struct clk_cache cc;
@@ -289,21 +298,17 @@ static void print_hwparams(struct snd_pcm_substream *substream,
{
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printd("%s HWPARAMS\n", name);
- snd_printd(" samplerate %d Hz\n", params_rate(p));
- snd_printd(" channels %d\n", params_channels(p));
- snd_printd(" format %d\n", params_format(p));
- snd_printd(" subformat %d\n", params_subformat(p));
- snd_printd(" buffer %d B\n", params_buffer_bytes(p));
- snd_printd(" period %d B\n", params_period_bytes(p));
- snd_printd(" access %d\n", params_access(p));
- snd_printd(" period_size %d\n", params_period_size(p));
- snd_printd(" periods %d\n", params_periods(p));
- snd_printd(" buffer_size %d\n", params_buffer_size(p));
- snd_printd(" %d B/s\n", params_rate(p) *
- params_channels(p) *
+ snd_printdd("%s HWPARAMS\n", name);
+ snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n",
+ params_rate(p), params_channels(p),
+ params_format(p), params_subformat(p));
+ snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n",
+ params_buffer_bytes(p), params_period_bytes(p),
+ params_period_size(p), params_periods(p));
+ snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n",
+ params_buffer_size(p), params_access(p),
+ params_rate(p) * params_channels(p) *
snd_pcm_format_width(params_format(p)) / 8);
-
}
static snd_pcm_format_t hpi_to_alsa_formats[] = {
@@ -375,7 +380,7 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&asihpi->pci->dev,
"No local sampleclock, err %d\n", err);
}
@@ -481,7 +486,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
params_buffer_bytes(params), runtime->dma_addr);
if (err == 0) {
snd_printdd(
- "stream_host_buffer_attach succeeded %u %lu\n",
+ "stream_host_buffer_attach success %u %lu\n",
params_buffer_bytes(params),
(unsigned long)runtime->dma_addr);
} else {
@@ -491,12 +496,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
}
err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
- &dpcm->hpi_buffer_attached,
- NULL, NULL, NULL);
-
- snd_printdd("stream_host_buffer_attach status 0x%x\n",
- dpcm->hpi_buffer_attached);
-
+ &dpcm->hpi_buffer_attached, NULL, NULL, NULL);
}
bytes_per_sec = params_rate(params) * params_channels(params);
width = snd_pcm_format_width(params_format(params));
@@ -538,7 +538,7 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
int expiry;
expiry = HZ / 200;
- /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
+
expiry = max(expiry, 1); /* don't let it be zero! */
dpcm->timer.expires = jiffies + expiry;
dpcm->respawn_timer = 1;
@@ -554,6 +554,48 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
del_timer(&dpcm->timer);
}
+static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)
+{
+ struct snd_card_asihpi_pcm *dpcm;
+ struct snd_card_asihpi *card;
+
+ BUG_ON(!substream);
+
+ dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;
+ card = snd_pcm_substream_chip(substream);
+
+ BUG_ON(in_interrupt());
+ tasklet_disable(&card->t);
+ card->llmode_streampriv = dpcm;
+ tasklet_enable(&card->t);
+
+ hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE,
+ card->update_interval_frames, 0));
+}
+
+static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_card_asihpi_pcm *dpcm;
+ struct snd_card_asihpi *card;
+
+ BUG_ON(!substream);
+
+ dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;
+ card = snd_pcm_substream_chip(substream);
+
+ hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
+
+ if (in_interrupt())
+ card->llmode_streampriv = NULL;
+ else {
+ tasklet_disable(&card->t);
+ card->llmode_streampriv = NULL;
+ tasklet_enable(&card->t);
+ }
+}
+
static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
int cmd)
{
@@ -564,10 +606,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printdd("%s trigger\n", name);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ snd_printdd("%s trigger start\n", name);
snd_pcm_group_for_each_entry(s, substream) {
struct snd_pcm_runtime *runtime = s->runtime;
struct snd_card_asihpi_pcm *ds = runtime->private_data;
@@ -588,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
* data??
*/
unsigned int preload = ds->period_bytes * 1;
- snd_printddd("%d preload x%x\n", s->number, preload);
+ snd_printddd("%d preload %d\n", s->number, preload);
hpi_handle_error(hpi_outstream_write_buf(
ds->h_stream,
&runtime->dma_area[0],
@@ -611,16 +653,16 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
} else
break;
}
- snd_printdd("start\n");
/* start the master stream */
- snd_card_asihpi_pcm_timer_start(substream);
+ card->pcm_start(substream);
if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
!card->can_dma)
hpi_handle_error(hpi_stream_start(dpcm->h_stream));
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_card_asihpi_pcm_timer_stop(substream);
+ snd_printdd("%s trigger stop\n", name);
+ card->pcm_stop(substream);
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) != card)
continue;
@@ -638,7 +680,6 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
} else
break;
}
- snd_printdd("stop\n");
/* _prepare and _hwparams reset the stream */
hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
@@ -651,13 +692,13 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printdd("pause release\n");
+ snd_printdd("%s trigger pause release\n", name);
+ card->pcm_start(substream);
hpi_handle_error(hpi_stream_start(dpcm->h_stream));
- snd_card_asihpi_pcm_timer_start(substream);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printdd("pause\n");
- snd_card_asihpi_pcm_timer_stop(substream);
+ snd_printdd("%s trigger pause push\n", name);
+ card->pcm_stop(substream);
hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
break;
default:
@@ -729,9 +770,8 @@ static void snd_card_asihpi_timer_function(unsigned long data)
u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
char name[16];
- snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printdd("%s snd_card_asihpi_timer_function\n", name);
+ snd_pcm_debug_name(substream, name, sizeof(name));
/* find minimum newdata and buffer pos in group */
snd_pcm_group_for_each_entry(s, substream) {
@@ -769,10 +809,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
s->number);
ds->drained_count++;
if (ds->drained_count > 20) {
- unsigned long flags;
- snd_pcm_stream_lock_irqsave(s, flags);
- snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(s, flags);
+ snd_pcm_stop_xrun(s);
continue;
}
} else {
@@ -794,19 +831,21 @@ static void snd_card_asihpi_timer_function(unsigned long data)
newdata);
}
- snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
+ snd_printddd(
+ "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n",
+ name, s->number, state,
+ ds->pcm_buf_elapsed_dma_ofs,
+ ds->pcm_buf_host_rw_ofs,
+ pcm_buf_dma_ofs,
+ (int)bytes_avail,
+
+ (int)on_card_bytes,
+ buffer_size-bytes_avail,
(unsigned long)frames_to_bytes(runtime,
runtime->status->hw_ptr),
(unsigned long)frames_to_bytes(runtime,
- runtime->control->appl_ptr));
-
- snd_printdd("%d S=%d, "
- "rw=0x%04X, dma=0x%04X, left=0x%04X, "
- "aux=0x%04X space=0x%04X\n",
- s->number, state,
- ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
- (int)bytes_avail,
- (int)on_card_bytes, buffer_size-bytes_avail);
+ runtime->control->appl_ptr)
+ );
loops++;
}
pcm_buf_dma_ofs = min_buf_pos;
@@ -824,16 +863,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
next_jiffies = max(next_jiffies, 1U);
dpcm->timer.expires = jiffies + next_jiffies;
- snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
+ snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",
next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
snd_pcm_group_for_each_entry(s, substream) {
struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
+ runtime = s->runtime;
/* don't link Cap and Play */
if (substream->stream != s->stream)
continue;
+ /* Store dma offset for use by pointer callback */
ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
if (xfercount &&
@@ -856,7 +897,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
}
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_printddd("P%d write1 0x%04X 0x%04X\n",
+ snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n",
s->number, xfer1, buf_ofs);
hpi_handle_error(
hpi_outstream_write_buf(
@@ -866,7 +907,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("P%d write2 0x%04X 0x%04X\n",
+ snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n",
s->number,
xfercount - xfer1, buf_ofs);
hpi_handle_error(
@@ -876,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
&ds->format));
}
} else {
- snd_printddd("C%d read1 0x%04x\n",
+ snd_printddd("read1, C=%d, xfer=%d\n",
s->number, xfer1);
hpi_handle_error(
hpi_instream_read_buf(
@@ -884,7 +925,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
pd, xfer1));
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("C%d read2 0x%04x\n",
+ snd_printddd("read2, C=%d, xfer=%d\n",
s->number, xfer2);
hpi_handle_error(
hpi_instream_read_buf(
@@ -892,16 +933,38 @@ static void snd_card_asihpi_timer_function(unsigned long data)
pd, xfer2));
}
}
+ /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */
ds->pcm_buf_host_rw_ofs += xfercount;
ds->pcm_buf_elapsed_dma_ofs += xfercount;
snd_pcm_period_elapsed(s);
}
}
- if (dpcm->respawn_timer)
+ if (!card->hpi->interrupt_mode && dpcm->respawn_timer)
add_timer(&dpcm->timer);
}
+static void snd_card_asihpi_int_task(unsigned long data)
+{
+ struct hpi_adapter *a = (struct hpi_adapter *)data;
+ struct snd_card_asihpi *asihpi;
+
+ WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
+ asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
+ if (asihpi->llmode_streampriv)
+ snd_card_asihpi_timer_function(
+ (unsigned long)asihpi->llmode_streampriv);
+}
+
+static void snd_card_asihpi_isr(struct hpi_adapter *a)
+{
+ struct snd_card_asihpi *asihpi;
+
+ WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
+ asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
+ tasklet_schedule(&asihpi->t);
+}
+
/***************************** PLAYBACK OPS ****************/
static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
@@ -937,7 +1000,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
snd_pcm_debug_name(substream, name, sizeof(name));
ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
- snd_printddd("%s pointer = 0x%04lx\n", name, (unsigned long)ptr);
+ snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr);
return ptr;
}
@@ -1009,13 +1072,22 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_card_asihpi_runtime_free;
memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback));
- snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
- snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
- /*?snd_card_asihpi_playback.period_bytes_min =
- card->out_max_chans * 4096; */
- snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
- snd_card_asihpi_playback.periods_min = PERIODS_MIN;
- snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ if (!card->hpi->interrupt_mode) {
+ snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
+ snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_playback.periods_min = PERIODS_MIN;
+ snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ } else {
+ size_t pbmin = card->update_interval_frames *
+ card->out_max_chans;
+ snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_playback.period_bytes_min = pbmin;
+ snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_playback.periods_min = PERIODS_MIN;
+ snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin;
+ }
+
/* snd_card_asihpi_playback.fifo_size = 0; */
snd_card_asihpi_playback.channels_max = card->out_max_chans;
snd_card_asihpi_playback.channels_min = card->out_min_chans;
@@ -1050,7 +1122,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
card->update_interval_frames);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- card->update_interval_frames * 2, UINT_MAX);
+ card->update_interval_frames, UINT_MAX);
snd_printdd("playback open\n");
@@ -1085,9 +1157,10 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+ char name[16];
+ snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printddd("capture pointer %d=%d\n",
- substream->number, dpcm->pcm_buf_dma_ofs);
+ snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);
/* NOTE Unlike playback can't use actual samples_played
for the capture position, because those samples aren't yet in
the local buffer available for reading.
@@ -1115,8 +1188,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
return 0;
}
-
-
static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
u32 h_stream)
{
@@ -1183,11 +1254,21 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_card_asihpi_runtime_free;
memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture));
- snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
- snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
- snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
- snd_card_asihpi_capture.periods_min = PERIODS_MIN;
- snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ if (!card->hpi->interrupt_mode) {
+ snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
+ snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_capture.periods_min = PERIODS_MIN;
+ snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ } else {
+ size_t pbmin = card->update_interval_frames *
+ card->out_max_chans;
+ snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_capture.period_bytes_min = pbmin;
+ snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_capture.periods_min = PERIODS_MIN;
+ snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin;
+ }
/* snd_card_asihpi_capture.fifo_size = 0; */
snd_card_asihpi_capture.channels_max = card->in_max_chans;
snd_card_asihpi_capture.channels_min = card->in_min_chans;
@@ -1212,7 +1293,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
card->update_interval_frames);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- card->update_interval_frames * 2, UINT_MAX);
+ card->update_interval_frames, UINT_MAX);
snd_pcm_set_sync(substream);
@@ -1296,8 +1377,9 @@ static const char * const asihpi_tuner_band_names[] = {
"TV PAL I",
"TV PAL DK",
"TV SECAM",
+ "TV DAB",
};
-
+/* Number of strings must match the enumerations for HPI_TUNER_BAND in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_tuner_band_names) ==
(HPI_TUNER_BAND_LAST+1)),
@@ -1317,9 +1399,11 @@ static const char * const asihpi_src_names[] = {
"Analog",
"Adapter",
"RTP",
- "Internal"
+ "Internal",
+ "AVB",
+ "BLU-Link"
};
-
+/* Number of strings must match the enumerations for HPI_SOURCENODES in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_src_names) ==
(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
@@ -1335,8 +1419,11 @@ static const char * const asihpi_dst_names[] = {
"Net",
"Analog",
"RTP",
+ "AVB",
+ "Internal",
+ "BLU-Link"
};
-
+/* Number of strings must match the enumerations for HPI_DESTNODES in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_dst_names) ==
(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
@@ -1351,7 +1438,7 @@ static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
if (err < 0)
return err;
else if (mixer_dump)
- snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
+ dev_info(&asihpi->pci->dev, "added %s(%d)\n", ctl->name, ctl->index);
return 0;
}
@@ -1625,18 +1712,7 @@ static const char * const asihpi_aesebu_format_names[] = {
static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, asihpi_aesebu_format_names);
}
static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
@@ -1863,22 +1939,7 @@ static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
if (num_bands < 0)
return num_bands;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_bands;
-
- if (num_bands > 0) {
- if (uinfo->value.enumerated.item >=
- uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- asihpi_tuner_band_names[
- tuner_bands[uinfo->value.enumerated.item]]);
-
- }
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_bands, asihpi_tuner_band_names);
}
static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
@@ -2253,7 +2314,7 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
u16 mode;
int i;
- u16 mode_map[6];
+ const char *mapped_names[6];
int valid_modes = 0;
/* HPI channel mode values can be from 1 to 6
@@ -2262,24 +2323,14 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
if (!hpi_channel_mode_query_mode(
h_control, i, &mode)) {
- mode_map[valid_modes] = mode;
+ mapped_names[valid_modes] = mode_names[mode];
valid_modes++;
}
if (!valid_modes)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = valid_modes;
-
- if (uinfo->value.enumerated.item >= valid_modes)
- uinfo->value.enumerated.item = valid_modes - 1;
-
- strcpy(uinfo->value.enumerated.name,
- mode_names[mode_map[uinfo->value.enumerated.item]]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, valid_modes, mapped_names);
}
static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
@@ -2328,13 +2379,18 @@ static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
/*------------------------------------------------------------
Sampleclock source controls
------------------------------------------------------------*/
-static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
+static const char const *sampleclock_sources[] = {
"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
"SMPTE", "Digital1", "Auto", "Network", "Invalid",
- "Prev Module",
+ "Prev Module", "BLU-Link",
"Digital2", "Digital3", "Digital4", "Digital5",
"Digital6", "Digital7", "Digital8"};
+ /* Number of strings must match expected enumerated values */
+ compile_time_assert(
+ (ARRAY_SIZE(sampleclock_sources) == MAX_CLOCKSOURCES),
+ assert_sampleclock_sources_size);
+
static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2482,15 +2538,19 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
struct hpi_control *hpi_ctl)
{
- struct snd_card *card = asihpi->card;
+ struct snd_card *card;
struct snd_kcontrol_new snd_control;
- struct clk_cache *clkcache = &asihpi->cc;
+ struct clk_cache *clkcache;
u32 hSC = hpi_ctl->h_control;
int has_aes_in = 0;
int i, j;
u16 source;
+ if (snd_BUG_ON(!asihpi))
+ return -EINVAL;
+ card = asihpi->card;
+ clkcache = &asihpi->cc;
snd_control.private_value = hpi_ctl->h_control;
clkcache->has_local = 0;
@@ -2592,7 +2652,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (err) {
if (err == HPI_ERROR_CONTROL_DISABLED) {
if (mixer_dump)
- snd_printk(KERN_INFO
+ dev_info(&asihpi->pci->dev,
"Disabled HPI Control(%d)\n",
idx);
continue;
@@ -2657,9 +2717,8 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
case HPI_CONTROL_COMPANDER:
default:
if (mixer_dump)
- snd_printk(KERN_INFO
- "Untranslated HPI Control"
- "(%d) %d %d %d %d %d\n",
+ dev_info(&asihpi->pci->dev,
+ "Untranslated HPI Control (%d) %d %d %d %d %d\n",
idx,
hpi_ctl.control_type,
hpi_ctl.src_node_type,
@@ -2674,7 +2733,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (HPI_ERROR_INVALID_OBJ_INDEX != err)
hpi_handle_error(err);
- snd_printk(KERN_INFO "%d mixer controls found\n", idx);
+ dev_info(&asihpi->pci->dev, "%d mixer controls found\n", idx);
return 0;
}
@@ -2837,8 +2896,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
&card);
if (err < 0)
return err;
- snd_printk(KERN_WARNING
- "**** WARNING **** Adapter index %d->ALSA index %d\n",
+ dev_warn(&pci_dev->dev, "Adapter index %d->ALSA index %d\n",
adapter_index, card->number);
}
@@ -2846,9 +2904,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
asihpi->card = card;
asihpi->pci = pci_dev;
asihpi->hpi = hpi;
-
- snd_printk(KERN_INFO "adapter ID=%4X index=%d\n",
- asihpi->hpi->adapter->type, adapter_index);
+ hpi->snd_card = card;
err = hpi_adapter_get_property(adapter_index,
HPI_ADAPTER_PROPERTY_CAPS1,
@@ -2868,8 +2924,16 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
if (err)
asihpi->update_interval_frames = 512;
- if (!asihpi->can_dma)
- asihpi->update_interval_frames *= 2;
+ if (hpi->interrupt_mode) {
+ asihpi->pcm_start = snd_card_asihpi_pcm_int_start;
+ asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;
+ tasklet_init(&asihpi->t, snd_card_asihpi_int_task,
+ (unsigned long)hpi);
+ hpi->interrupt_callback = snd_card_asihpi_isr;
+ } else {
+ asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;
+ asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop;
+ }
hpi_handle_error(hpi_instream_open(adapter_index,
0, &h_stream));
@@ -2879,6 +2943,9 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
hpi_handle_error(hpi_instream_close(h_stream));
+ if (!asihpi->can_dma)
+ asihpi->update_interval_frames *= 2;
+
err = hpi_adapter_get_property(adapter_index,
HPI_ADAPTER_PROPERTY_CURCHANNELS,
&asihpi->in_max_chans, &asihpi->out_max_chans);
@@ -2896,20 +2963,21 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
asihpi->in_min_chans = 1;
}
- snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n",
+ dev_info(&pci_dev->dev, "Has dma:%d, grouping:%d, mrx:%d, uif:%d\n",
asihpi->can_dma,
asihpi->support_grouping,
- asihpi->support_mrx
+ asihpi->support_mrx,
+ asihpi->update_interval_frames
);
err = snd_card_asihpi_pcm_new(asihpi, 0);
if (err < 0) {
- snd_printk(KERN_ERR "pcm_new failed\n");
+ dev_err(&pci_dev->dev, "pcm_new failed\n");
goto __nodev;
}
err = snd_card_asihpi_mixer_new(asihpi);
if (err < 0) {
- snd_printk(KERN_ERR "mixer_new failed\n");
+ dev_err(&pci_dev->dev, "mixer_new failed\n");
goto __nodev;
}
@@ -2936,13 +3004,12 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
err = snd_card_register(card);
if (!err) {
- hpi->snd_card = card;
dev++;
return 0;
}
__nodev:
snd_card_free(card);
- snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
+ dev_err(&pci_dev->dev, "snd_asihpi_probe error %d\n", err);
return err;
}
@@ -2950,6 +3017,16 @@ __nodev:
static void snd_asihpi_remove(struct pci_dev *pci_dev)
{
struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);
+ struct snd_card_asihpi *asihpi = hpi->snd_card->private_data;
+
+ /* Stop interrupts */
+ if (hpi->interrupt_mode) {
+ hpi->interrupt_callback = NULL;
+ hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
+ tasklet_kill(&asihpi->t);
+ }
+
snd_card_free(hpi->snd_card);
hpi->snd_card = NULL;
asihpi_adapter_remove(pci_dev);
@@ -2971,10 +3048,6 @@ static struct pci_driver driver = {
.id_table = asihpi_pci_tbl,
.probe = snd_asihpi_probe,
.remove = snd_asihpi_remove,
-#ifdef CONFIG_PM_SLEEP
-/* .suspend = snd_asihpi_suspend,
- .resume = snd_asihpi_resume, */
-#endif
};
static int __init snd_asihpi_init(void)
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 20887241a3ae..4466bd2c5272 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -196,8 +196,10 @@ enum HPI_SOURCENODES {
packets of RTP audio samples from other devices. */
HPI_SOURCENODE_RTP_DESTINATION = 112,
HPI_SOURCENODE_INTERNAL = 113, /**< node internal to the device. */
+ HPI_SOURCENODE_AVB = 114, /**< AVB input stream */
+ HPI_SOURCENODE_BLULINK = 115, /**< BLU-link input channel */
/* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */
- HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */
+ HPI_SOURCENODE_LAST_INDEX = 115 /**< largest ID */
/* AX6 max sourcenode types = 15 */
};
@@ -224,8 +226,11 @@ enum HPI_DESTNODES {
/** RTP stream output node - This node is a source for
packets of RTP audio samples that are sent to other devices. */
HPI_DESTNODE_RTP_SOURCE = 208,
+ HPI_DESTNODE_AVB = 209, /**< AVB output stream */
+ HPI_DESTNODE_INTERNAL = 210, /**< node internal to the device. */
+ HPI_DESTNODE_BLULINK = 211, /**< BLU-link output channel. */
/* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
- HPI_DESTNODE_LAST_INDEX = 208 /**< largest ID */
+ HPI_DESTNODE_LAST_INDEX = 211 /**< largest ID */
/* AX6 max destnode types = 15 */
};
@@ -752,7 +757,8 @@ enum HPI_TUNER_BAND {
HPI_TUNER_BAND_TV_PAL_I = 7, /**< PAL-I TV band*/
HPI_TUNER_BAND_TV_PAL_DK = 8, /**< PAL-D/K TV band*/
HPI_TUNER_BAND_TV_SECAM_L = 9, /**< SECAM-L TV band*/
- HPI_TUNER_BAND_LAST = 9 /**< the index of the last tuner band. */
+ HPI_TUNER_BAND_DAB = 10,
+ HPI_TUNER_BAND_LAST = 10 /**< the index of the last tuner band. */
};
/** Tuner mode attributes
@@ -842,8 +848,10 @@ enum HPI_SAMPLECLOCK_SOURCES {
HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
/** From previous adjacent module (ASI2416 only)*/
HPI_SAMPLECLOCK_SOURCE_PREV_MODULE = 10,
+/** Blu link sample clock*/
+ HPI_SAMPLECLOCK_SOURCE_BLULINK = 11,
/*! Update this if you add a new clock source.*/
- HPI_SAMPLECLOCK_SOURCE_LAST = 10
+ HPI_SAMPLECLOCK_SOURCE_LAST = 11
};
/** Equalizer filter types. Used by HPI_ParametricEq_SetBand()
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 4f2873880b16..8d5abfa4e24b 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -163,6 +163,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
static void delete_adapter_obj(struct hpi_adapter_obj *pao);
+static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
+ u32 message);
+
static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr);
@@ -283,7 +286,6 @@ static void adapter_message(struct hpi_adapter_obj *pao,
case HPI_ADAPTER_DELETE:
adapter_delete(pao, phm, phr);
break;
-
default:
hw_message(pao, phm, phr);
break;
@@ -673,6 +675,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
+ pao->irq_query_and_clear = adapter_irq_query_and_clear;
+ pao->instream_host_buffer_status =
+ phw->p_interface_buffer->instream_host_buffer_status;
+ pao->outstream_host_buffer_status =
+ phw->p_interface_buffer->outstream_host_buffer_status;
+
return hpi_add_adapter(pao);
}
@@ -713,6 +721,21 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
/*****************************************************************************/
/* Adapter functions */
+static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
+ u32 message)
+{
+ struct hpi_hw_obj *phw = pao->priv;
+ u32 hsr = 0;
+
+ hsr = ioread32(phw->prHSR);
+ if (hsr & C6205_HSR_INTSRC) {
+ /* reset the interrupt from the DSP */
+ iowrite32(C6205_HSR_INTSRC, phw->prHSR);
+ return HPI_IRQ_MIXER;
+ }
+
+ return HPI_IRQ_NONE;
+}
/*****************************************************************************/
/* OutStream Host buffer functions */
@@ -1331,17 +1354,21 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
if (boot_code_id[1] != 0) {
/* DSP 1 is a C6713 */
/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
- boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
+ boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202);
hpios_delay_micro_seconds(100);
/* Reset the 6713 #1 - revB */
boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
-
- /* dummy read every 4 words for 6205 advisory 1.4.4 */
- boot_loader_read_mem32(pao, 0, 0);
-
+ /* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */
+ if (0 != (boot_loader_read_mem32(pao, 0,
+ (C6205_BAR0_TIMER1_CTL)) & ~8))
+ return HPI6205_ERROR_6205_REG;
hpios_delay_micro_seconds(100);
+
/* Release C6713 from reset - revB */
boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
+ if (4 != (boot_loader_read_mem32(pao, 0,
+ (C6205_BAR0_TIMER1_CTL)) & ~8))
+ return HPI6205_ERROR_6205_REG;
hpios_delay_micro_seconds(100);
}
@@ -2089,7 +2116,7 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
return 0;
}
- /* Assume buffer of type struct bus_master_interface
+ /* Assume buffer of type struct bus_master_interface_62
is allocated "noncacheable" */
if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index bc86cb726d79..48380ce2c81b 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -554,17 +554,21 @@ struct hpi_pci {
struct pci_dev *pci_dev;
};
+/** Adapter specification resource */
+struct hpi_adapter_specification {
+ u32 type;
+ u8 modules[4];
+};
+
struct hpi_resource {
union {
const struct hpi_pci *pci;
const char *net_if;
+ struct hpi_adapter_specification adapter_spec;
+ const void *sw_if;
} r;
-#ifndef HPI64BIT /* keep structure size constant */
- u32 pad_to64;
-#endif
u16 bus_type; /* HPI_BUS_PNPISA, _PCI, _USB etc */
u16 padding;
-
};
/** Format info used inside struct hpi_message
@@ -582,7 +586,7 @@ struct hpi_msg_format {
struct hpi_msg_data {
struct hpi_msg_format format;
u8 *pb_data;
-#ifndef HPI64BIT
+#ifndef CONFIG_64BIT
u32 padding;
#endif
u32 data_size;
@@ -595,7 +599,7 @@ struct hpi_data_legacy32 {
u32 data_size;
};
-#ifdef HPI64BIT
+#ifdef CONFIG_64BIT
/* Compatibility version of struct hpi_data*/
struct hpi_data_compat32 {
struct hpi_msg_format format;
@@ -682,8 +686,8 @@ union hpi_adapterx_msg {
u16 value;
} test_assert;
struct {
- u32 yes;
- } irq_query;
+ u32 message;
+ } irq;
u32 pad[3];
};
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index 7ed5c26c3737..c7751243dc42 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -206,6 +206,14 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
struct hpi_control_cache_info *info =
(struct hpi_control_cache_info *)
&p_master_cache[byte_count];
+ u16 control_index = info->control_index;
+
+ if (control_index >= pC->control_count) {
+ HPI_DEBUG_LOG(INFO,
+ "adap %d control index %d out of range, cache not ready?\n",
+ pC->adap_idx, control_index);
+ return 0;
+ }
if (!info->size_in32bit_words) {
if (!i) {
@@ -225,10 +233,10 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
}
if (info->control_type) {
- pC->p_info[info->control_index] = info;
+ pC->p_info[control_index] = info;
cached++;
} else { /* dummy cache entry */
- pC->p_info[info->control_index] = NULL;
+ pC->p_info[control_index] = NULL;
}
byte_count += info->size_in32bit_words * 4;
@@ -309,35 +317,18 @@ static const struct pad_ofs_size pad_desc[] = {
/** CheckControlCache checks the cache and fills the struct hpi_response
* accordingly. It returns one if a cache hit occurred, zero otherwise.
*/
-short hpi_check_control_cache(struct hpi_control_cache *p_cache,
+short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
struct hpi_message *phm, struct hpi_response *phr)
{
- short found = 1;
- struct hpi_control_cache_info *pI;
- struct hpi_control_cache_single *pC;
size_t response_size;
- if (!find_control(phm->obj_index, p_cache, &pI)) {
- HPI_DEBUG_LOG(VERBOSE,
- "HPICMN find_control() failed for adap %d\n",
- phm->adapter_index);
- return 0;
- }
-
- phr->error = 0;
- phr->specific_error = 0;
- phr->version = 0;
+ short found = 1;
/* set the default response size */
response_size =
sizeof(struct hpi_response_header) +
sizeof(struct hpi_control_res);
- /* pC is the default cached control strucure. May be cast to
- something else in the following switch statement.
- */
- pC = (struct hpi_control_cache_single *)pI;
-
- switch (pI->control_type) {
+ switch (pC->u.i.control_type) {
case HPI_CONTROL_METER:
if (phm->u.c.attribute == HPI_METER_PEAK) {
@@ -467,7 +458,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
break;
case HPI_CONTROL_PAD:{
struct hpi_control_cache_pad *p_pad;
- p_pad = (struct hpi_control_cache_pad *)pI;
+ p_pad = (struct hpi_control_cache_pad *)pC;
if (!(p_pad->field_valid_flags & (1 <<
HPI_CTL_ATTR_INDEX(phm->u.c.
@@ -531,7 +522,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
found ? "Cached" : "Uncached", phm->adapter_index,
- pI->control_index, pI->control_type, phm->u.c.attribute);
+ pC->u.i.control_index, pC->u.i.control_type,
+ phm->u.c.attribute);
if (found) {
phr->size = (u16)response_size;
@@ -543,34 +535,36 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
return found;
}
-/** Updates the cache with Set values.
-
-Only update if no error.
-Volume and Level return the limited values in the response, so use these
-Multiplexer does so use sent values
-*/
-void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
+short hpi_check_control_cache(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
- struct hpi_control_cache_single *pC;
struct hpi_control_cache_info *pI;
- if (phr->error)
- return;
-
if (!find_control(phm->obj_index, p_cache, &pI)) {
HPI_DEBUG_LOG(VERBOSE,
"HPICMN find_control() failed for adap %d\n",
phm->adapter_index);
- return;
+ return 0;
}
- /* pC is the default cached control strucure.
- May be cast to something else in the following switch statement.
- */
- pC = (struct hpi_control_cache_single *)pI;
+ phr->error = 0;
+ phr->specific_error = 0;
+ phr->version = 0;
+
+ return hpi_check_control_cache_single((struct hpi_control_cache_single
+ *)pI, phm, phr);
+}
+
+/** Updates the cache with Set values.
- switch (pI->control_type) {
+Only update if no error.
+Volume and Level return the limited values in the response, so use these
+Multiplexer does so use sent values
+*/
+void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
+ *pC, struct hpi_message *phm, struct hpi_response *phr)
+{
+ switch (pC->u.i.control_type) {
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
@@ -625,6 +619,30 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
}
}
+void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
+ struct hpi_message *phm, struct hpi_response *phr)
+{
+ struct hpi_control_cache_single *pC;
+ struct hpi_control_cache_info *pI;
+
+ if (phr->error)
+ return;
+
+ if (!find_control(phm->obj_index, p_cache, &pI)) {
+ HPI_DEBUG_LOG(VERBOSE,
+ "HPICMN find_control() failed for adap %d\n",
+ phm->adapter_index);
+ return;
+ }
+
+ /* pC is the default cached control strucure.
+ May be cast to something else in the following switch statement.
+ */
+ pC = (struct hpi_control_cache_single *)pI;
+
+ hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
+}
+
/** Allocate control cache.
\return Cache pointer, or NULL if allocation fails.
@@ -637,12 +655,13 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
if (!p_cache)
return NULL;
- p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info),
- GFP_KERNEL);
+ p_cache->p_info =
+ kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
if (!p_cache->p_info) {
kfree(p_cache);
return NULL;
}
+
p_cache->cache_size_in_bytes = size_in_bytes;
p_cache->control_count = control_count;
p_cache->p_cache = p_dsp_control_buffer;
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h
index e44121283047..46629c2d101b 100644
--- a/sound/pci/asihpi/hpicmn.h
+++ b/sound/pci/asihpi/hpicmn.h
@@ -1,7 +1,7 @@
/**
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -21,7 +21,11 @@
struct hpi_adapter_obj;
/* a function that takes an adapter obj and returns an int */
-typedef int adapter_int_func(struct hpi_adapter_obj *pao);
+typedef int adapter_int_func(struct hpi_adapter_obj *pao, u32 message);
+
+#define HPI_IRQ_NONE (0)
+#define HPI_IRQ_MESSAGE (1)
+#define HPI_IRQ_MIXER (2)
struct hpi_adapter_obj {
struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */
@@ -33,6 +37,9 @@ struct hpi_adapter_obj {
u16 dsp_crashed;
u16 has_control_cache;
void *priv;
+ adapter_int_func *irq_query_and_clear;
+ struct hpi_hostbuffer_status *instream_host_buffer_status;
+ struct hpi_hostbuffer_status *outstream_host_buffer_status;
};
struct hpi_control_cache {
@@ -55,13 +62,21 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao);
short hpi_check_control_cache(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
+
+short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
+ struct hpi_message *phm, struct hpi_response *phr);
+
struct hpi_control_cache *hpi_alloc_control_cache(const u32
number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer);
+
void hpi_free_control_cache(struct hpi_control_cache *p_cache);
void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
+void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
+ *pC, struct hpi_message *phm, struct hpi_response *phr);
+
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
hpi_handler_func HPI_COMMON;
diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c
index 032d563e3708..7eb617175fde 100644
--- a/sound/pci/asihpi/hpimsginit.c
+++ b/sound/pci/asihpi/hpimsginit.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -37,11 +37,15 @@ static u16 gwSSX2_bypass;
static void hpi_init_message(struct hpi_message *phm, u16 object,
u16 function)
{
- memset(phm, 0, sizeof(*phm));
+ u16 size;
+
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
- phm->size = msg_size[object];
+ size = msg_size[object];
else
- phm->size = sizeof(*phm);
+ size = sizeof(*phm);
+
+ memset(phm, 0, size);
+ phm->size = size;
if (gwSSX2_bypass)
phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
@@ -60,12 +64,16 @@ static void hpi_init_message(struct hpi_message *phm, u16 object,
void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
u16 error)
{
- memset(phr, 0, sizeof(*phr));
- phr->type = HPI_TYPE_RESPONSE;
+ u16 size;
+
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
- phr->size = res_size[object];
+ size = res_size[object];
else
- phr->size = sizeof(*phr);
+ size = sizeof(*phr);
+
+ memset(phr, 0, sizeof(*phr));
+ phr->size = size;
+ phr->type = HPI_TYPE_RESPONSE;
phr->object = object;
phr->function = function;
phr->error = error;
@@ -86,7 +94,7 @@ void hpi_init_message_response(struct hpi_message *phm,
static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
u16 object, u16 function)
{
- memset(phm, 0, sizeof(*phm));
+ memset(phm, 0, size);
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
phm->size = size;
phm->type = HPI_TYPE_REQUEST;
@@ -100,7 +108,9 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
u16 object, u16 function)
{
- memset(phr, 0, sizeof(*phr));
+ (void)object;
+ (void)function;
+ memset(phr, 0, size);
phr->size = size;
phr->version = 1;
phr->type = HPI_TYPE_RESPONSE;
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index d4790ddc225c..736f45337fc7 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -35,6 +35,7 @@ static struct pci_device_id asihpi_pci_tbl[] = {
static struct hpios_spinlock msgx_lock;
static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS];
+static int logging_enabled = 1;
static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
*pci_info)
@@ -312,7 +313,9 @@ static void instream_message(struct hpi_message *phm,
void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
- HPI_DEBUG_MESSAGE(DEBUG, phm);
+
+ if (logging_enabled)
+ HPI_DEBUG_MESSAGE(DEBUG, phm);
if (phm->type != HPI_TYPE_REQUEST) {
hpi_init_response(phr, phm->object, phm->function,
@@ -352,8 +355,14 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
hw_entry_point(phm, phr);
break;
}
- HPI_DEBUG_RESPONSE(phr);
+ if (logging_enabled)
+ HPI_DEBUG_RESPONSE(phr);
+
+ if (phr->error >= HPI_ERROR_DSP_COMMUNICATION) {
+ hpi_debug_level_set(HPI_DEBUG_LEVEL_ERROR);
+ logging_enabled = 0;
+ }
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr)
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 7f0272032fbb..6aa677e60555 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -1,7 +1,8 @@
/*******************************************************************************
-
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Common Linux HPI ioctl and module probe/remove functions
+
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -12,11 +13,6 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Common Linux HPI ioctl and module probe/remove functions
*******************************************************************************/
#define SOURCEFILE_NAME "hpioctl.c"
@@ -29,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
#include "hpicmn.h"
#include <linux/fs.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
@@ -307,10 +304,38 @@ out:
return err;
}
+static int asihpi_irq_count;
+
+static irqreturn_t asihpi_isr(int irq, void *dev_id)
+{
+ struct hpi_adapter *a = dev_id;
+ int handled;
+
+ if (!a->adapter->irq_query_and_clear) {
+ pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type,
+ a->adapter->index);
+ return IRQ_NONE;
+ }
+
+ handled = a->adapter->irq_query_and_clear(a->adapter, 0);
+
+ if (!handled)
+ return IRQ_NONE;
+
+ asihpi_irq_count++;
+ /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n",
+ asihpi_irq_count, a->adapter->type, a->adapter->index); */
+
+ if (a->interrupt_callback)
+ a->interrupt_callback(a);
+
+ return IRQ_HANDLED;
+}
+
int asihpi_adapter_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
- int idx, nm;
+ int idx, nm, low_latency_mode = 0, irq_supported = 0;
int adapter_index;
unsigned int memlen;
struct hpi_message hm;
@@ -388,8 +413,38 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
hm.adapter_index = adapter.adapter->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
- if (hr.error)
+ if (hr.error) {
+ HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n");
goto err;
+ }
+
+ /* Check if current mode == Low Latency mode */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_GET_MODE);
+ hm.adapter_index = adapter.adapter->index;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+
+ if (!hr.error
+ && hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY)
+ low_latency_mode = 1;
+ else
+ dev_info(&pci_dev->dev,
+ "Adapter at index %d is not in low latency mode\n",
+ adapter.adapter->index);
+
+ /* Check if IRQs are supported */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_GET_PROPERTY);
+ hm.adapter_index = adapter.adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+ if (hr.error || !hr.u.ax.property_get.parameter1) {
+ dev_info(&pci_dev->dev,
+ "IRQs not supported by adapter at index %d\n",
+ adapter.adapter->index);
+ } else {
+ irq_supported = 1;
+ }
/* WARNING can't init mutex in 'adapter'
* and then copy it to adapters[] ?!?!
@@ -398,6 +453,44 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
mutex_init(&adapters[adapter_index].mutex);
pci_set_drvdata(pci_dev, &adapters[adapter_index]);
+ if (low_latency_mode && irq_supported) {
+ if (!adapter.adapter->irq_query_and_clear) {
+ dev_err(&pci_dev->dev,
+ "no IRQ handler for adapter %d, aborting\n",
+ adapter.adapter->index);
+ goto err;
+ }
+
+ /* Disable IRQ generation on DSP side by setting the rate to 0 */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_SET_PROPERTY);
+ hm.adapter_index = adapter.adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
+ hm.u.ax.property_set.parameter1 = 0;
+ hm.u.ax.property_set.parameter2 = 0;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+ if (hr.error) {
+ HPI_DEBUG_LOG(ERROR,
+ "HPI_ADAPTER_GET_MODE failed, aborting\n");
+ goto err;
+ }
+
+ /* Note: request_irq calls asihpi_isr here */
+ if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED,
+ "asihpi", &adapters[adapter_index])) {
+ dev_err(&pci_dev->dev, "request_irq(%d) failed\n",
+ pci_dev->irq);
+ goto err;
+ }
+
+ adapters[adapter_index].interrupt_mode = 1;
+
+ dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq);
+ adapters[adapter_index].irq = pci_dev->irq;
+ } else {
+ dev_info(&pci_dev->dev, "using polled mode\n");
+ }
+
dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n",
adapter.adapter->type, adapter_index);
@@ -431,6 +524,15 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
pa = pci_get_drvdata(pci_dev);
pci = pa->adapter->pci;
+ /* Disable IRQ generation on DSP side */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_SET_PROPERTY);
+ hm.adapter_index = pa->adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
+ hm.u.ax.property_set.parameter1 = 0;
+ hm.u.ax.property_set.parameter2 = 0;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_DELETE);
hm.adapter_index = pa->adapter->index;
@@ -442,8 +544,10 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
iounmap(pci.ap_mem_base[idx]);
}
- if (pa->p_buffer)
- vfree(pa->p_buffer);
+ if (pa->irq)
+ free_irq(pa->irq, pa);
+
+ vfree(pa->p_buffer);
if (1)
dev_info(&pci_dev->dev,
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h
index d3fbd0d76c37..4e383601b9cf 100644
--- a/sound/pci/asihpi/hpios.h
+++ b/sound/pci/asihpi/hpios.h
@@ -41,10 +41,6 @@ HPI Operating System Specific macros for Linux Kernel driver
#define HPI_NO_OS_FILE_OPS
-#ifdef CONFIG_64BIT
-#define HPI64BIT
-#endif
-
/** Details of a memory area allocated with pci_alloc_consistent
Need all info for parameters to pci_free_consistent
*/
@@ -155,6 +151,10 @@ struct hpi_adapter {
struct hpi_adapter_obj *adapter;
struct snd_card *snd_card;
+ int irq;
+ int interrupt_mode;
+ void (*interrupt_callback) (struct hpi_adapter *);
+
/* mutex prevents contention for one card
between multiple user programs (via ioctl) */
struct mutex mutex;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 7895c5d300c7..9c1c4452a8ee 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -688,9 +688,7 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
if (! dma->substream || ! dma->running)
return;
dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
- snd_pcm_stream_lock(dma->substream);
- snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(dma->substream);
+ snd_pcm_stop_xrun(dma->substream);
}
/*
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 3c3241309a30..b2f63e0727de 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -638,9 +638,7 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
if (! dma->substream || ! dma->running)
return;
dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
- snd_pcm_stream_lock(dma->substream);
- snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(dma->substream);
+ snd_pcm_stop_xrun(dma->substream);
}
/*
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 21ce31f636bc..996369134ea8 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -48,11 +48,10 @@ static void vortex_fix_latency(struct pci_dev *vortex)
{
int rc;
if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
- pr_info( CARD_NAME
- ": vortex latency is 0xff\n");
+ dev_info(&vortex->dev, "vortex latency is 0xff\n");
} else {
- pr_warn( CARD_NAME
- ": could not set vortex latency: pci error 0x%x\n", rc);
+ dev_warn(&vortex->dev,
+ "could not set vortex latency: pci error 0x%x\n", rc);
}
}
@@ -70,11 +69,10 @@ static void vortex_fix_agp_bridge(struct pci_dev *via)
if (!(rc = pci_read_config_byte(via, 0x42, &value))
&& ((value & 0x10)
|| !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
- pr_info( CARD_NAME
- ": bridge config is 0x%x\n", value | 0x10);
+ dev_info(&via->dev, "bridge config is 0x%x\n", value | 0x10);
} else {
- pr_warn( CARD_NAME
- ": could not set vortex latency: pci error 0x%x\n", rc);
+ dev_warn(&via->dev,
+ "could not set vortex latency: pci error 0x%x\n", rc);
}
}
@@ -97,7 +95,8 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix)
PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
}
if (via) {
- pr_info( CARD_NAME ": Activating latency workaround...\n");
+ dev_info(&vortex->dev,
+ "Activating latency workaround...\n");
vortex_fix_latency(vortex);
vortex_fix_agp_bridge(via);
}
@@ -153,7 +152,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- pr_err( "error to set DMA mask\n");
+ dev_err(card->dev, "error to set DMA mask\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -182,7 +181,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
chip->mmio = pci_ioremap_bar(pci, 0);
if (!chip->mmio) {
- pr_err( "MMIO area remap failed.\n");
+ dev_err(card->dev, "MMIO area remap failed.\n");
err = -ENOMEM;
goto ioremap_out;
}
@@ -191,14 +190,14 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
* This must be done before we do request_irq otherwise we can get spurious
* interrupts that we do not handle properly and make a mess of things */
if ((err = vortex_core_init(chip)) != 0) {
- pr_err( "hw core init failed\n");
+ dev_err(card->dev, "hw core init failed\n");
goto core_out;
}
if ((err = request_irq(pci->irq, vortex_interrupt,
IRQF_SHARED, KBUILD_MODNAME,
chip)) != 0) {
- pr_err( "cannot grab irq\n");
+ dev_err(card->dev, "cannot grab irq\n");
goto irq_out;
}
chip->irq = pci->irq;
@@ -315,7 +314,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
sizeof(snd_vortex_synth_arg_t), &wave) < 0
|| wave == NULL) {
- snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n");
+ dev_err(card->dev, "Can't initialize Aureal wavetable synth\n");
} else {
snd_vortex_synth_arg_t *arg;
@@ -342,11 +341,11 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
chip->rev = pci->revision;
#ifdef CHIP_AU8830
if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
- pr_alert(
- "vortex: The revision (%x) of your card has not been seen before.\n",
+ dev_alert(card->dev,
+ "The revision (%x) of your card has not been seen before.\n",
chip->rev);
- pr_alert(
- "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
+ dev_alert(card->dev,
+ "Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
snd_card_free(card);
err = -ENODEV;
return err;
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 466a5c8e8354..3a8fefefea77 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -243,7 +243,7 @@ static int vortex_core_init(vortex_t * card);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
static irqreturn_t vortex_interrupt(int irq, void *dev_id);
-static int vortex_alsafmt_aspfmt(int alsafmt);
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v);
/* Connection stuff. */
static void vortex_connect_default(vortex_t * vortex, int en);
@@ -278,7 +278,7 @@ static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
static void vortex_Vort3D_enable(vortex_t * v);
static void vortex_Vort3D_disable(vortex_t * v);
static void vortex_Vort3D_connect(vortex_t * vortex, int en);
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v);
#endif
/* Driver stuff. */
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index 30f760e3d2c0..ab0f87312911 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -484,12 +484,13 @@ static void a3dsrc_ZeroState(a3dsrc_t * a)
}
/* Reset entire A3D engine */
-static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
+static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v)
{
int i, var, var2;
if ((a->vortex) == NULL) {
- pr_err( "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
+ dev_err(v->card->dev,
+ "ZeroStateA3D: ERROR: a->vortex is NULL\n");
return;
}
@@ -601,7 +602,7 @@ static void vortex_Vort3D_enable(vortex_t *v)
Vort3DRend_Initialize(v, XT_HEADPHONE);
for (i = 0; i < NR_A3D; i++) {
vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
- a3dsrc_ZeroStateA3D(&(v->a3d[0]));
+ a3dsrc_ZeroStateA3D(&v->a3d[0], v);
}
/* Register ALSA controls */
vortex_a3d_register_controls(v);
@@ -628,15 +629,15 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
v->mixxtlk[0] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[0] < 0) {
- pr_warn
- ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+ dev_warn(v->card->dev,
+ "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
v->mixxtlk[1] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[1] < 0) {
- pr_warn
- ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+ dev_warn(v->card->dev,
+ "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
#endif
@@ -676,11 +677,11 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
}
/* Initialize one single A3D source. */
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v)
{
if (a->vortex == NULL) {
- pr_warn
- ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
+ dev_warn(v->card->dev,
+ "Vort3D_InitializeSource: A3D source not initialized\n");
return;
}
if (en) {
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 72e81286b70e..4667c3232b7f 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -285,8 +285,8 @@ vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
temp = hwread(vortex->mmio, prev);
//printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
if ((++lifeboat) > 0xf) {
- pr_err(
- "vortex_mixer_addWTD: lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "vortex_mixer_addWTD: lifeboat overflow\n");
return 0;
}
}
@@ -303,7 +303,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
if (((1 << ch) & eax) == 0) {
- pr_err( "mix ALARM %x\n", eax);
+ dev_err(vortex->card->dev, "mix ALARM %x\n", eax);
return 0;
}
ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
@@ -324,8 +324,8 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
//printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
while ((edx & 0xf) != mix) {
if ((esi) > 0xf) {
- pr_err(
- "vortex: mixdelWTD: error lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "mixdelWTD: error lifeboat overflow\n");
return 0;
}
esp14 = ebx;
@@ -492,7 +492,7 @@ vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio)
hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
if ((++lifeboat) > 0x9) {
- pr_err( "Vortex: Src cvr fail\n");
+ dev_err(vortex->card->dev, "Src cvr fail\n");
break;
}
}
@@ -684,8 +684,8 @@ vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
temp = hwread(vortex->mmio, prev);
//printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
if ((++lifeboat) > 0xf) {
- pr_err(
- "vortex_src_addWTD: lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "vortex_src_addWTD: lifeboat overflow\n");
return 0;
}
}
@@ -703,7 +703,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
if (((1 << ch) & eax) == 0) {
- pr_err( "src alarm\n");
+ dev_err(vortex->card->dev, "src alarm\n");
return 0;
}
ebp = VORTEX_SRC_CHNBASE + (ch << 2);
@@ -724,8 +724,8 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
//printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
while ((edx & 0xf) != src) {
if ((esi) > 0xf) {
- pr_warn
- ("vortex: srcdelWTD: error, lifeboat overflow\n");
+ dev_warn(vortex->card->dev,
+ "srcdelWTD: error, lifeboat overflow\n");
return 0;
}
esp14 = ebx;
@@ -819,8 +819,8 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority,
do {
temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
if (lifeboat++ > 0xbb8) {
- pr_err(
- "Vortex: vortex_fifo_setadbctrl fail\n");
+ dev_err(vortex->card->dev,
+ "vortex_fifo_setadbctrl fail\n");
break;
}
}
@@ -915,7 +915,8 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
do {
temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
if (lifeboat++ > 0xbb8) {
- pr_err( "Vortex: vortex_fifo_setwtctrl fail\n");
+ dev_err(vortex->card->dev,
+ "vortex_fifo_setwtctrl fail\n");
break;
}
}
@@ -1042,7 +1043,7 @@ static void vortex_fifo_init(vortex_t * vortex)
for (x = NR_ADB - 1; x >= 0; x--) {
hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
- pr_err( "bad adb fifo reset!");
+ dev_err(vortex->card->dev, "bad adb fifo reset!");
vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
addr -= 4;
}
@@ -1053,9 +1054,9 @@ static void vortex_fifo_init(vortex_t * vortex)
for (x = NR_WT - 1; x >= 0; x--) {
hwwrite(vortex->mmio, addr, FIFO_U0);
if (hwread(vortex->mmio, addr) != FIFO_U0)
- pr_err(
- "bad wt fifo reset (0x%08x, 0x%08x)!\n",
- addr, hwread(vortex->mmio, addr));
+ dev_err(vortex->card->dev,
+ "bad wt fifo reset (0x%08x, 0x%08x)!\n",
+ addr, hwread(vortex->mmio, addr));
vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
addr -= 4;
}
@@ -1213,8 +1214,9 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
if (dma->period_virt >= dma->nr_periods)
dma->period_virt -= dma->nr_periods;
if (delta != 1)
- pr_info( "vortex: %d virt=%d, real=%d, delta=%d\n",
- adbdma, dma->period_virt, dma->period_real, delta);
+ dev_info(vortex->card->dev,
+ "%d virt=%d, real=%d, delta=%d\n",
+ adbdma, dma->period_virt, dma->period_real, delta);
return delta;
}
@@ -1482,8 +1484,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
dma->period_real = page;
if (delta != 1)
- pr_warn( "vortex: wt virt = %d, delta = %d\n",
- dma->period_virt, delta);
+ dev_warn(vortex->card->dev, "wt virt = %d, delta = %d\n",
+ dma->period_virt, delta);
return delta;
}
@@ -1667,9 +1669,9 @@ vortex_adb_addroutes(vortex_t * vortex, unsigned char channel,
hwread(vortex->mmio,
VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
if ((lifeboat++) > ADB_MASK) {
- pr_err(
- "vortex_adb_addroutes: unending route! 0x%x\n",
- *route);
+ dev_err(vortex->card->dev,
+ "vortex_adb_addroutes: unending route! 0x%x\n",
+ *route);
return;
}
}
@@ -1703,9 +1705,9 @@ vortex_adb_delroutes(vortex_t * vortex, unsigned char channel,
hwread(vortex->mmio,
VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
- pr_err(
- "vortex_adb_delroutes: route not found! 0x%x\n",
- route0);
+ dev_err(vortex->card->dev,
+ "vortex_adb_delroutes: route not found! 0x%x\n",
+ route0);
return;
}
}
@@ -2045,7 +2047,9 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
}
}
}
- pr_err( "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
+ dev_err(vortex->card->dev,
+ "FATAL: ResManager: resource type %d exhausted.\n",
+ restype);
return -ENOMEM;
}
@@ -2173,11 +2177,13 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
memset(stream->resources, 0,
sizeof(unsigned char) *
VORTEX_RESOURCE_LAST);
- pr_err( "vortex: out of A3D sources. Sorry\n");
+ dev_err(vortex->card->dev,
+ "out of A3D sources. Sorry\n");
return -EBUSY;
}
/* (De)Initialize A3D hardware source. */
- vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en);
+ vortex_Vort3D_InitializeSource(&vortex->a3d[a3d], en,
+ vortex);
}
/* Make SPDIF out exclusive to "spdif" device when in use. */
if ((stream->type == VORTEX_PCM_SPDIF) && (en)) {
@@ -2421,7 +2427,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
// Is at least one IRQ flag set?
if (source == 0) {
- pr_err( "vortex: missing irq source\n");
+ dev_err(vortex->card->dev, "missing irq source\n");
return IRQ_NONE;
}
@@ -2429,19 +2435,19 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
// Attend every interrupt source.
if (unlikely(source & IRQ_ERR_MASK)) {
if (source & IRQ_FATAL) {
- pr_err( "vortex: IRQ fatal error\n");
+ dev_err(vortex->card->dev, "IRQ fatal error\n");
}
if (source & IRQ_PARITY) {
- pr_err( "vortex: IRQ parity error\n");
+ dev_err(vortex->card->dev, "IRQ parity error\n");
}
if (source & IRQ_REG) {
- pr_err( "vortex: IRQ reg error\n");
+ dev_err(vortex->card->dev, "IRQ reg error\n");
}
if (source & IRQ_FIFO) {
- pr_err( "vortex: IRQ fifo error\n");
+ dev_err(vortex->card->dev, "IRQ fifo error\n");
}
if (source & IRQ_DMA) {
- pr_err( "vortex: IRQ dma error\n");
+ dev_err(vortex->card->dev, "IRQ dma error\n");
}
handled = 1;
}
@@ -2489,7 +2495,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
}
if (!handled) {
- pr_err( "vortex: unknown irq source %x\n", source);
+ dev_err(vortex->card->dev, "unknown irq source %x\n", source);
}
return IRQ_RETVAL(handled);
}
@@ -2546,7 +2552,7 @@ vortex_codec_write(struct snd_ac97 * codec, unsigned short addr, unsigned short
while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
udelay(100);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 codec stuck busy\n");
+ dev_err(card->card->dev, "ac97 codec stuck busy\n");
return;
}
}
@@ -2572,7 +2578,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
udelay(100);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 codec stuck busy\n");
+ dev_err(card->card->dev, "ac97 codec stuck busy\n");
return 0xffff;
}
}
@@ -2586,7 +2592,8 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
udelay(100);
data = hwread(card->mmio, VORTEX_CODEC_IO);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 address never arrived\n");
+ dev_err(card->card->dev,
+ "ac97 address never arrived\n");
return 0xffff;
}
} while ((data & VORTEX_CODEC_ADDMASK) !=
@@ -2683,7 +2690,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode)
static int vortex_core_init(vortex_t *vortex)
{
- pr_info( "Vortex: init.... ");
+ dev_info(vortex->card->dev, "init started\n");
/* Hardware Init. */
hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
msleep(5);
@@ -2728,7 +2735,7 @@ static int vortex_core_init(vortex_t *vortex)
//vortex_enable_timer_int(vortex);
//vortex_disable_timer_int(vortex);
- pr_info( "done.\n");
+ dev_info(vortex->card->dev, "init.... done.\n");
spin_lock_init(&vortex->lock);
return 0;
@@ -2737,7 +2744,7 @@ static int vortex_core_init(vortex_t *vortex)
static int vortex_core_shutdown(vortex_t * vortex)
{
- pr_info( "Vortex: shutdown...");
+ dev_info(vortex->card->dev, "shutdown started\n");
#ifndef CHIP_AU8820
vortex_eq_free(vortex);
vortex_Vort3D_disable(vortex);
@@ -2759,13 +2766,13 @@ static int vortex_core_shutdown(vortex_t * vortex)
msleep(5);
hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
- pr_info( "done.\n");
+ dev_info(vortex->card->dev, "shutdown.... done.\n");
return 0;
}
/* Alsa support. */
-static int vortex_alsafmt_aspfmt(int alsafmt)
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v)
{
int fmt;
@@ -2793,7 +2800,8 @@ static int vortex_alsafmt_aspfmt(int alsafmt)
break;
default:
fmt = 0x8;
- pr_err( "vortex: format unsupported %d\n", alsafmt);
+ dev_err(v->card->dev,
+ "format unsupported %d\n", alsafmt);
break;
}
return fmt;
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 9404ba73eaf6..9585c5c63b96 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -845,7 +845,8 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
if (count != 20) {
- pr_err( "vortex: peak count error 20 != %d \n", count);
+ dev_err(vortex->card->dev,
+ "peak count error 20 != %d\n", count);
return -1;
}
for (i = 0; i < 20; i++)
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
index 72daf6cf8169..151815b857a0 100644
--- a/sound/pci/au88x0/au88x0_game.c
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -98,7 +98,8 @@ static int vortex_gameport_register(vortex_t *vortex)
vortex->gameport = gp = gameport_allocate_port();
if (!gp) {
- pr_err( "vortex: cannot allocate memory for gameport\n");
+ dev_err(vortex->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
index 328c1943c0c3..1025e55ca854 100644
--- a/sound/pci/au88x0/au88x0_mpu401.c
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -73,7 +73,7 @@ static int snd_vortex_midi(vortex_t *vortex)
/* Check if anything is OK. */
temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
if (temp != MPU401_ACK /*0xfe */ ) {
- pr_err( "midi port doesn't acknowledge!\n");
+ dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n");
return -ENODEV;
}
/* Enable MPU401 interrupts. */
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 5adc6b92ffab..a6d6d8d0867a 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -227,7 +227,7 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
err =
snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0) {
- pr_err( "Vortex: pcm page alloc failed!\n");
+ dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n");
return err;
}
/*
@@ -332,7 +332,7 @@ static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
dir = 1;
else
dir = 0;
- fmt = vortex_alsafmt_aspfmt(runtime->format);
+ fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
spin_lock_irq(&chip->lock);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
@@ -371,7 +371,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
#ifndef CHIP_AU8810
else {
- pr_info( "vortex: wt start %d\n", dma);
+ dev_info(chip->card->dev, "wt start %d\n", dma);
vortex_wtdma_startfifo(chip, dma);
}
#endif
@@ -384,7 +384,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
vortex_adbdma_stopfifo(chip, dma);
#ifndef CHIP_AU8810
else {
- pr_info( "vortex: wt stop %d\n", dma);
+ dev_info(chip->card->dev, "wt stop %d\n", dma);
vortex_wtdma_stopfifo(chip, dma);
}
#endif
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index f094bac24291..78e12f4796f3 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
temp = hwread(vortex->mmio, WT_PARM(wt, 3));
- pr_debug( "vortex: WT PARM3: %x\n", temp);
+ dev_dbg(vortex->card->dev, "WT PARM3: %x\n", temp);
//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
@@ -98,7 +98,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
- pr_debug( "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+ dev_dbg(vortex->card->dev, "WT GMODE: %x\n",
+ hwread(vortex->mmio, WT_GMODE(wt)));
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
@@ -106,7 +107,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
voice->parm0 = voice->parm1 = 0xcfb23e2f;
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
- pr_debug( "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+ dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n",
+ hwread(vortex->mmio, WT_GMODE(wt)));
return 0;
}
@@ -196,14 +198,15 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
if (wt >= (NR_WT / NR_WT_PB)) {
- pr_warn
- ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
- reg, wt);
+ dev_warn(vortex->card->dev,
+ "WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
+ reg, wt);
return 0;
}
} else {
if (wt >= NR_WT) {
- pr_err( "vortex: WT SetReg: voice out of range\n");
+ dev_err(vortex->card->dev,
+ "WT SetReg: voice out of range\n");
return 0;
}
}
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 3878cf5de9a4..e1cf01949fda 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -725,19 +725,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Analog", "Digital"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) {
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- }
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 5a69e26cb2fb..fdbb9c05c77b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1034,11 +1034,6 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
const char * const *p = NULL;
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1;
- uinfo->value.enumerated.items = reg.enum_c;
- if (uinfo->value.enumerated.item > reg.enum_c - 1U)
- uinfo->value.enumerated.item = reg.enum_c - 1U;
if (reg.reg == IDX_MIXER_ADVCTL2) {
switch(reg.lchan_shift) {
case 8: /* modem out sel */
@@ -1051,12 +1046,12 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
p = texts4;
break;
}
- } else
- if (reg.reg == IDX_MIXER_REC_SELECT)
+ } else if (reg.reg == IDX_MIXER_REC_SELECT)
p = texts3;
- strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo,
+ (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1,
+ reg.enum_c, p);
}
static int
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 27de0de90018..68c0eb0a2807 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -185,17 +185,11 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[6] = {
+ static const char * const texts[6] = {
"IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 6;
- if (uinfo->value.enumerated.item > 5)
- uinfo->value.enumerated.item = 5;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 6, texts);
}
static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -228,17 +222,11 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[6] = {
+ static const char * const texts[4] = {
"Phone", "Mic", "Line in", "Aux"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -273,29 +261,17 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Side out", "Line in" };
+ static const char * const texts[2] = { "Side out", "Line in" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Line in", "Mic in" };
+ static const char * const texts[2] = { "Line in", "Mic in" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 454659074390..977a59855fa6 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -438,7 +438,9 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
position = src->ops->get_ca(src);
if (position < apcm->vm_block->addr) {
- snd_printdd("ctxfi: bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", position, apcm->vm_block->addr, apcm->vm_block->size);
+ dev_dbg(atc->card->dev,
+ "bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n",
+ position, apcm->vm_block->addr, apcm->vm_block->size);
position = apcm->vm_block->addr;
}
@@ -1145,7 +1147,6 @@ static int atc_release_resources(struct ct_atc *atc)
int i;
struct daio_mgr *daio_mgr = NULL;
struct dao *dao = NULL;
- struct dai *dai = NULL;
struct daio *daio = NULL;
struct sum_mgr *sum_mgr = NULL;
struct src_mgr *src_mgr = NULL;
@@ -1172,9 +1173,6 @@ static int atc_release_resources(struct ct_atc *atc)
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
- } else {
- dai = container_of(daio, struct dai, daio);
- /* some thing to do for dai ... */
}
daio_mgr->put_daio(daio_mgr, daio);
}
@@ -1299,7 +1297,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
atc->model = CT20K2_UNKNOWN;
}
atc->model_name = ct_subsys_name[atc->model];
- snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
+ dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
atc->chip_name, atc->model_name,
vendor_id, device_id);
return 0;
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index c1c3f8816fff..9b87dd28de83 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -528,8 +528,6 @@ static int get_daio_rsc(struct daio_mgr *mgr,
struct daio **rdaio)
{
int err;
- struct dai *dai = NULL;
- struct dao *dao = NULL;
unsigned long flags;
*rdaio = NULL;
@@ -544,27 +542,30 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return err;
}
+ err = -ENOMEM;
/* Allocate mem for daio resource */
if (desc->type <= DAIO_OUT_MAX) {
- dao = kzalloc(sizeof(*dao), GFP_KERNEL);
- if (!dao) {
- err = -ENOMEM;
+ struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
+ if (!dao)
goto error;
- }
+
err = dao_rsc_init(dao, desc, mgr);
- if (err)
+ if (err) {
+ kfree(dao);
goto error;
+ }
*rdaio = &dao->daio;
} else {
- dai = kzalloc(sizeof(*dai), GFP_KERNEL);
- if (!dai) {
- err = -ENOMEM;
+ struct dai *dai = kzalloc(sizeof(*dai), GFP_KERNEL);
+ if (!dai)
goto error;
- }
+
err = dai_rsc_init(dai, desc, mgr);
- if (err)
+ if (err) {
+ kfree(dai);
goto error;
+ }
*rdaio = &dai->daio;
}
@@ -575,11 +576,6 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return 0;
error:
- if (dao)
- kfree(dao);
- else if (dai)
- kfree(dai);
-
spin_lock_irqsave(&mgr->mgr_lock, flags);
daio_mgr_put_rsc(&mgr->mgr, desc->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index 03fb909085af..a5d460453d7b 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -421,12 +421,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc)
atimer->atc = atc;
hw = atc->hw;
if (!use_system_timer && hw->set_timer_irq) {
- snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
+ dev_info(atc->card->dev, "Use xfi-native timer\n");
atimer->ops = &ct_xfitimer_ops;
hw->irq_callback_data = atimer;
hw->irq_callback = ct_timer_interrupt;
} else {
- snd_printd(KERN_INFO "ctxfi: Use system timer\n");
+ dev_info(atc->card->dev, "Use system timer\n");
atimer->ops = &ct_systimer_ops;
}
return atimer;
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c
index 20c7cbc89bb3..febee5bda877 100644
--- a/sound/pci/echoaudio/darla20_dsp.c
+++ b/sound/pci/echoaudio/darla20_dsp.c
@@ -33,12 +33,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Darla20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw: could not initialize DSP comm page\n");
return err;
}
@@ -57,7 +57,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c
index 6da6663e9176..7b4f6fd51b09 100644
--- a/sound/pci/echoaudio/darla24_dsp.c
+++ b/sound/pci/echoaudio/darla24_dsp.c
@@ -33,12 +33,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Darla24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw: could not initialize DSP comm page\n");
return err;
}
@@ -56,7 +56,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -128,15 +127,17 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GD24_8000;
break;
default:
- DE_ACT(("set_sample_rate: Error, invalid sample rate %d\n",
- rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: Error, invalid sample rate %d\n",
+ rate);
return -EINVAL;
}
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
chip->sample_rate = rate;
/* Override the sample rate if this card is set to Echo sync. */
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index 3cdc2ee2d1dd..ae11ce11b1c2 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -46,12 +46,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
int err;
local_irq_enable();
- DE_INIT(("init_hw() - Echo3G\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -98,7 +98,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 631aaa4046ad..21228adaa70c 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -48,13 +48,16 @@ static int get_firmware(const struct firmware **fw_entry,
#ifdef CONFIG_PM_SLEEP
if (chip->fw_cache[fw_index]) {
- DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
+ dev_dbg(chip->card->dev,
+ "firmware requested: %s is cached\n",
+ card_fw[fw_index].data);
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
#endif
- DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
+ dev_dbg(chip->card->dev,
+ "firmware requested: %s\n", card_fw[fw_index].data);
snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
@@ -69,13 +72,13 @@ static int get_firmware(const struct firmware **fw_entry,
-static void free_firmware(const struct firmware *fw_entry)
+static void free_firmware(const struct firmware *fw_entry,
+ struct echoaudio *chip)
{
#ifdef CONFIG_PM_SLEEP
- DE_ACT(("firmware not released (kept in cache)\n"));
+ dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n");
#else
release_firmware(fw_entry);
- DE_ACT(("firmware released\n"));
#endif
}
@@ -89,10 +92,9 @@ static void free_firmware_cache(struct echoaudio *chip)
for (i = 0; i < 8 ; i++)
if (chip->fw_cache[i]) {
release_firmware(chip->fw_cache[i]);
- DE_ACT(("release_firmware(%d)\n", i));
+ dev_dbg(chip->card->dev, "release_firmware(%d)\n", i);
}
- DE_ACT(("firmware_cache released\n"));
#endif
}
@@ -286,7 +288,7 @@ static int pcm_open(struct snd_pcm_substream *substream,
/* Set up hw capabilities and contraints */
memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware));
- DE_HWP(("max_channels=%d\n", max_channels));
+ dev_dbg(chip->card->dev, "max_channels=%d\n", max_channels);
pipe->constr.list = channels_list;
pipe->constr.mask = 0;
for (i = 0; channels_list[i] <= max_channels; i++);
@@ -336,7 +338,7 @@ static int pcm_open(struct snd_pcm_substream *substream,
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
PAGE_SIZE, &pipe->sgpage)) < 0) {
- DE_HWP(("s-g list allocation failed\n"));
+ dev_err(chip->card->dev, "s-g list allocation failed\n");
return err;
}
@@ -350,7 +352,6 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err;
- DE_ACT(("pcm_analog_in_open\n"));
if ((err = pcm_open(substream, num_analog_busses_in(chip) -
substream->number)) < 0)
return err;
@@ -367,9 +368,9 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream)
atomic_inc(&chip->opencount);
if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
chip->can_set_rate=0;
- DE_HWP(("pcm_analog_in_open cs=%d oc=%d r=%d\n",
+ dev_dbg(chip->card->dev, "pcm_analog_in_open cs=%d oc=%d r=%d\n",
chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
+ chip->sample_rate);
return 0;
}
@@ -385,7 +386,6 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream)
#else
max_channels = num_analog_busses_out(chip);
#endif
- DE_ACT(("pcm_analog_out_open\n"));
if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
return err;
if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
@@ -403,9 +403,9 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream)
atomic_inc(&chip->opencount);
if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
chip->can_set_rate=0;
- DE_HWP(("pcm_analog_out_open cs=%d oc=%d r=%d\n",
+ dev_dbg(chip->card->dev, "pcm_analog_out_open cs=%d oc=%d r=%d\n",
chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
+ chip->sample_rate);
return 0;
}
@@ -418,7 +418,6 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err, max_channels;
- DE_ACT(("pcm_digital_in_open\n"));
max_channels = num_digital_busses_in(chip) - substream->number;
mutex_lock(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
@@ -460,7 +459,6 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err, max_channels;
- DE_ACT(("pcm_digital_out_open\n"));
max_channels = num_digital_busses_out(chip) - substream->number;
mutex_lock(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
@@ -507,18 +505,17 @@ static int pcm_close(struct snd_pcm_substream *substream)
/* Nothing to do here. Audio is already off and pipe will be
* freed by its callback
*/
- DE_ACT(("pcm_close\n"));
atomic_dec(&chip->opencount);
oc = atomic_read(&chip->opencount);
- DE_ACT(("pcm_close oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate, chip->rate_set));
+ dev_dbg(chip->card->dev, "pcm_close oc=%d cs=%d rs=%d\n", oc,
+ chip->can_set_rate, chip->rate_set);
if (oc < 2)
chip->can_set_rate = 1;
if (oc == 0)
chip->rate_set = 0;
- DE_ACT(("pcm_close2 oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate,chip->rate_set));
+ dev_dbg(chip->card->dev, "pcm_close2 oc=%d cs=%d rs=%d\n", oc,
+ chip->can_set_rate, chip->rate_set);
return 0;
}
@@ -542,7 +539,7 @@ static int init_engine(struct snd_pcm_substream *substream,
*/
spin_lock_irq(&chip->lock);
if (pipe->index >= 0) {
- DE_HWP(("hwp_ie free(%d)\n", pipe->index));
+ dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
err = free_pipes(chip, pipe);
snd_BUG_ON(err);
chip->substream[pipe->index] = NULL;
@@ -551,16 +548,17 @@ static int init_engine(struct snd_pcm_substream *substream,
err = allocate_pipes(chip, pipe, pipe_index, interleave);
if (err < 0) {
spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n",
- pipe_index, err));
+ dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
+ pipe_index, err);
return err;
}
spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index));
+ dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index);
- DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
+ dev_dbg(chip->card->dev,
+ "pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
params_buffer_bytes(hw_params), params_periods(hw_params),
- params_period_bytes(hw_params)));
+ params_period_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (err < 0) {
@@ -615,7 +613,6 @@ static int init_engine(struct snd_pcm_substream *substream,
spin_lock_irq(&chip->lock);
set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_params ok\n"));
return 0;
}
@@ -679,14 +676,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
spin_lock_irq(&chip->lock);
if (pipe->index >= 0) {
- DE_HWP(("pcm_hw_free(%d)\n", pipe->index));
+ dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index);
free_pipes(chip, pipe);
chip->substream[pipe->index] = NULL;
pipe->index = -1;
}
spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_freed\n"));
snd_pcm_lib_free_pages(substream);
return 0;
}
@@ -700,8 +696,8 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
struct audioformat format;
int pipe_index = ((struct audiopipe *)runtime->private_data)->index;
- DE_HWP(("Prepare rate=%d format=%d channels=%d\n",
- runtime->rate, runtime->format, runtime->channels));
+ dev_dbg(chip->card->dev, "Prepare rate=%d format=%d channels=%d\n",
+ runtime->rate, runtime->format, runtime->channels);
format.interleave = runtime->channels;
format.data_are_bigendian = 0;
format.mono_to_stereo = 0;
@@ -721,8 +717,9 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
format.bits_per_sample = 32;
break;
default:
- DE_HWP(("Prepare error: unsupported format %d\n",
- runtime->format));
+ dev_err(chip->card->dev,
+ "Prepare error: unsupported format %d\n",
+ runtime->format);
return -EINVAL;
}
@@ -757,10 +754,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
- DE_ACT(("pcm_trigger resume\n"));
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- DE_ACT(("pcm_trigger start\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -782,9 +777,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
chip->pipe_cyclic_mask);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- DE_ACT(("pcm_trigger suspend\n"));
case SNDRV_PCM_TRIGGER_STOP:
- DE_ACT(("pcm_trigger stop\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -794,7 +787,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
err = stop_transport(chip, channelmask);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- DE_ACT(("pcm_trigger pause\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -931,7 +923,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Analog PCM ok\n"));
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital inputs, no outputs */
@@ -944,7 +935,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Digital PCM ok\n"));
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#else /* ECHOCARD_HAS_VMIXER */
@@ -966,7 +956,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Analog PCM ok\n"));
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital i/o */
@@ -981,7 +970,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Digital PCM ok\n"));
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#endif /* ECHOCARD_HAS_VMIXER */
@@ -1416,21 +1404,14 @@ static struct snd_kcontrol_new snd_echo_vmixer = {
static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[4] = {
+ static const char * const names[4] = {
"S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical",
"S/PDIF Cdrom"
};
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_digital_modes;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_digital_modes)
- uinfo->value.enumerated.item = chip->num_digital_modes - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->digital_mode_list[uinfo->value.enumerated.item]]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, chip->num_digital_modes, names);
}
static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol,
@@ -1481,7 +1462,8 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
snd_ctl_notify(chip->card,
SNDRV_CTL_EVENT_MASK_VALUE,
&chip->clock_src_ctl->id);
- DE_ACT(("SDM() =%d\n", changed));
+ dev_dbg(chip->card->dev,
+ "SDM() =%d\n", changed);
}
if (changed >= 0)
changed = 1; /* No errors */
@@ -1509,16 +1491,9 @@ static struct snd_kcontrol_new snd_echo_digital_mode_switch = {
static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[2] = {"Consumer", "Professional"};
+ static const char * const names[2] = {"Consumer", "Professional"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = 2;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- names[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, names);
}
static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol,
@@ -1566,21 +1541,14 @@ static struct snd_kcontrol_new snd_echo_spdif_mode_switch = {
static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[8] = {
+ static const char * const names[8] = {
"Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync",
"ESync96", "MTC"
};
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_clock_sources;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_clock_sources)
- uinfo->value.enumerated.item = chip->num_clock_sources - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->clock_source_list[uinfo->value.enumerated.item]]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, chip->num_clock_sources, names);
}
static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol,
@@ -1622,7 +1590,8 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
}
if (changed < 0)
- DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed));
+ dev_dbg(chip->card->dev,
+ "seticlk val%d err 0x%x\n", dclock, changed);
return changed;
}
@@ -1879,7 +1848,7 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
#ifdef ECHOCARD_HAS_MIDI
if (st > 0 && chip->midi_in) {
snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);
- DE_MID(("rawmidi_iread=%d\n", st));
+ dev_dbg(chip->card->dev, "rawmidi_iread=%d\n", st);
}
#endif
return IRQ_HANDLED;
@@ -1894,10 +1863,8 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
static int snd_echo_free(struct echoaudio *chip)
{
- DE_INIT(("Stop DSP...\n"));
if (chip->comm_page)
rest_in_peace(chip);
- DE_INIT(("Stopped.\n"));
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -1908,17 +1875,14 @@ static int snd_echo_free(struct echoaudio *chip)
if (chip->dsp_registers)
iounmap(chip->dsp_registers);
- if (chip->iores)
- release_and_free_resource(chip->iores);
+ release_and_free_resource(chip->iores);
- DE_INIT(("MMIO freed.\n"));
pci_disable_device(chip->pci);
/* release chip data */
free_firmware_cache(chip);
kfree(chip);
- DE_INIT(("Chip freed.\n"));
return 0;
}
@@ -1928,7 +1892,6 @@ static int snd_echo_dev_free(struct snd_device *device)
{
struct echoaudio *chip = device->device_data;
- DE_INIT(("snd_echo_dev_free()...\n"));
return snd_echo_free(chip);
}
@@ -1961,7 +1924,7 @@ static int snd_echo_create(struct snd_card *card,
pci_disable_device(pci);
return -ENOMEM;
}
- DE_INIT(("chip=%p\n", chip));
+ dev_dbg(card->dev, "chip=%p\n", chip);
spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
@@ -1998,8 +1961,8 @@ static int snd_echo_create(struct snd_card *card,
return -EBUSY;
}
chip->irq = pci->irq;
- DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",
- chip->pci, chip->irq, chip->pci->subsystem_device));
+ dev_dbg(card->dev, "pci=%p irq=%d subdev=%04x Init hardware...\n",
+ chip->pci, chip->irq, chip->pci->subsystem_device);
/* Create the DSP comm page - this is the area of memory used for most
of the communication with the DSP, which accesses it via bus mastering */
@@ -2017,11 +1980,10 @@ static int snd_echo_create(struct snd_card *card,
if (err >= 0)
err = set_mixer_defaults(chip);
if (err < 0) {
- DE_INIT(("init_hw err=%d\n", err));
+ dev_err(card->dev, "init_hw err=%d\n", err);
snd_echo_free(chip);
return err;
}
- DE_INIT(("Card init OK\n"));
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_echo_free(chip);
@@ -2051,7 +2013,6 @@ static int snd_echo_probe(struct pci_dev *pci,
return -ENOENT;
}
- DE_INIT(("Echoaudio driver starting...\n"));
i = 0;
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
@@ -2204,7 +2165,6 @@ static int snd_echo_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct echoaudio *chip = dev_get_drvdata(dev);
- DE_INIT(("suspend start\n"));
snd_pcm_suspend_all(chip->analog_pcm);
snd_pcm_suspend_all(chip->digital_pcm);
@@ -2231,7 +2191,6 @@ static int snd_echo_suspend(struct device *dev)
pci_save_state(pci);
pci_disable_device(pci);
- DE_INIT(("suspend done\n"));
return 0;
}
@@ -2245,7 +2204,6 @@ static int snd_echo_resume(struct device *dev)
u32 pipe_alloc_mask;
int err;
- DE_INIT(("resume start\n"));
pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
if (commpage_bak == NULL)
@@ -2256,11 +2214,10 @@ static int snd_echo_resume(struct device *dev)
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err < 0) {
kfree(commpage_bak);
- DE_INIT(("resume init_hw err=%d\n", err));
+ dev_err(dev, "resume init_hw err=%d\n", err);
snd_echo_free(chip);
return err;
}
- DE_INIT(("resume init OK\n"));
/* Temporarily set chip->pipe_alloc_mask=0 otherwise
* restore_dsp_settings() fails.
@@ -2273,7 +2230,6 @@ static int snd_echo_resume(struct device *dev)
kfree(commpage_bak);
return err;
}
- DE_INIT(("resume restore OK\n"));
memcpy(&commpage->audio_format, &commpage_bak->audio_format,
sizeof(commpage->audio_format));
@@ -2290,7 +2246,7 @@ static int snd_echo_resume(struct device *dev)
return -EBUSY;
}
chip->irq = pci->irq;
- DE_INIT(("resume irq=%d\n", chip->irq));
+ dev_dbg(dev, "resume irq=%d\n", chip->irq);
#ifdef ECHOCARD_HAS_MIDI
if (chip->midi_input_enabled)
@@ -2299,7 +2255,6 @@ static int snd_echo_resume(struct device *dev)
snd_echo_midi_output_trigger(chip->midi_out, 1);
#endif
- DE_INIT(("resume done\n"));
return 0;
}
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index b86b88da81cd..32515227a692 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -295,34 +295,6 @@
#define PIPE_STATE_PENDING 3 /* Pipe has pending start */
-/* Debug initialization */
-#ifdef CONFIG_SND_DEBUG
-#define DE_INIT(x) snd_printk x
-#else
-#define DE_INIT(x)
-#endif
-
-/* Debug hw_params callbacks */
-#ifdef CONFIG_SND_DEBUG
-#define DE_HWP(x) snd_printk x
-#else
-#define DE_HWP(x)
-#endif
-
-/* Debug normal activity (open, start, stop...) */
-#ifdef CONFIG_SND_DEBUG
-#define DE_ACT(x) snd_printk x
-#else
-#define DE_ACT(x)
-#endif
-
-/* Debug midi activity */
-#ifdef CONFIG_SND_DEBUG
-#define DE_MID(x) snd_printk x
-#else
-#define DE_MID(x)
-#endif
-
struct audiopipe {
volatile u32 *dma_counter; /* Commpage register that contains
@@ -468,7 +440,8 @@ static int wait_handshake(struct echoaudio *chip);
static int send_vector(struct echoaudio *chip, u32 command);
static int get_firmware(const struct firmware **fw_entry,
struct echoaudio *chip, const short fw_index);
-static void free_firmware(const struct firmware *fw_entry);
+static void free_firmware(const struct firmware *fw_entry,
+ struct echoaudio *chip);
#ifdef ECHOCARD_HAS_MIDI
static int enable_midi_input(struct echoaudio *chip, char enable);
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index 658db44ef746..2fa66dc3e675 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -51,7 +51,7 @@ static int check_asic_status(struct echoaudio *chip)
}
box_status = le32_to_cpu(chip->comm_page->ext_box_status);
- DE_INIT(("box_status=%x\n", box_status));
+ dev_dbg(chip->card->dev, "box_status=%x\n", box_status);
if (box_status == E3G_ASIC_NOT_LOADED)
return -ENODEV;
@@ -76,7 +76,8 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq));
+ dev_dbg(chip->card->dev,
+ "WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq);
ctl = cpu_to_le32(ctl);
frq = cpu_to_le32(frq);
@@ -89,7 +90,7 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
}
- DE_ACT(("WriteControlReg: not written, no change\n"));
+ dev_dbg(chip->card->dev, "WriteControlReg: not written, no change\n");
return 0;
}
@@ -258,8 +259,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -313,7 +314,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("SetSampleRate: %d clock %x\n", rate, control_reg));
+ dev_dbg(chip->card->dev,
+ "SetSampleRate: %d clock %x\n", rate, control_reg);
/* Tell the DSP about it - DSP reads both control reg & freq reg */
return write_control_reg(chip, control_reg, frq_reg, 0);
@@ -326,7 +328,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
{
u32 control_reg, clocks_from_dsp;
- DE_ACT(("set_input_clock:\n"));
/* Mask off the clock select bits */
control_reg = le32_to_cpu(chip->comm_page->control_register) &
@@ -335,13 +336,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Echo3G clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
if (chip->digital_mode == DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Echo3G clock to SPDIF\n"));
control_reg |= E3G_SPDIF_CLOCK;
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= E3G_DOUBLE_SPEED_MODE;
@@ -351,12 +350,10 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Echo3G clock to ADAT\n"));
control_reg |= E3G_ADAT_CLOCK;
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Echo3G clock to WORD\n"));
control_reg |= E3G_WORD_CLOCK;
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96)
control_reg |= E3G_DOUBLE_SPEED_MODE;
@@ -364,7 +361,8 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Echo3G\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Echo3G\n", clock);
return -EINVAL;
}
@@ -392,7 +390,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -427,6 +426,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode(%d)\n", chip->digital_mode));
+ dev_dbg(chip->card->dev, "set_digital_mode(%d)\n", chip->digital_mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index 5a6a217b82e0..1a9427aabe1d 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -80,7 +80,7 @@ static int send_vector(struct echoaudio *chip, u32 command)
udelay(1);
}
- DE_ACT((KERN_ERR "timeout on send_vector\n"));
+ dev_err(chip->card->dev, "timeout on send_vector\n");
return -EBUSY;
}
@@ -104,7 +104,7 @@ static int write_dsp(struct echoaudio *chip, u32 data)
}
chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */
- DE_ACT((KERN_ERR "write_dsp: Set bad_board to TRUE\n"));
+ dev_dbg(chip->card->dev, "write_dsp: Set bad_board to TRUE\n");
return -EIO;
}
@@ -127,7 +127,7 @@ static int read_dsp(struct echoaudio *chip, u32 *data)
}
chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */
- DE_INIT((KERN_ERR "read_dsp: Set bad_board to TRUE\n"));
+ dev_err(chip->card->dev, "read_dsp: Set bad_board to TRUE\n");
return -EIO;
}
@@ -154,8 +154,9 @@ static int read_sn(struct echoaudio *chip)
return -EIO;
}
}
- DE_INIT(("Read serial number %08x %08x %08x %08x %08x\n",
- sn[0], sn[1], sn[2], sn[3], sn[4]));
+ dev_dbg(chip->card->dev,
+ "Read serial number %08x %08x %08x %08x %08x\n",
+ sn[0], sn[1], sn[2], sn[3], sn[4]);
return 0;
}
@@ -205,13 +206,12 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
goto la_error;
}
- DE_INIT(("ASIC loaded\n"));
- free_firmware(fw);
+ free_firmware(fw, chip);
return 0;
la_error:
- DE_INIT(("failed on write_dsp\n"));
- free_firmware(fw);
+ dev_err(chip->card->dev, "failed on write_dsp\n");
+ free_firmware(fw, chip);
return -EIO;
}
@@ -241,8 +241,9 @@ static int install_resident_loader(struct echoaudio *chip)
loader is already installed, host flag 5 will be on. */
status = get_dsp_register(chip, CHI32_STATUS_REG);
if (status & CHI32_STATUS_REG_HF5) {
- DE_INIT(("Resident loader already installed; status is 0x%x\n",
- status));
+ dev_dbg(chip->card->dev,
+ "Resident loader already installed; status is 0x%x\n",
+ status);
return 0;
}
@@ -283,12 +284,14 @@ static int install_resident_loader(struct echoaudio *chip)
/* Write the count to the DSP */
if (write_dsp(chip, words)) {
- DE_INIT(("install_resident_loader: Failed to write word count!\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write word count!\n");
goto irl_error;
}
/* Write the DSP address */
if (write_dsp(chip, address)) {
- DE_INIT(("install_resident_loader: Failed to write DSP address!\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write DSP address!\n");
goto irl_error;
}
/* Write out this block of code to the DSP */
@@ -297,7 +300,8 @@ static int install_resident_loader(struct echoaudio *chip)
data = ((u32)code[index] << 16) + code[index + 1];
if (write_dsp(chip, data)) {
- DE_INIT(("install_resident_loader: Failed to write DSP code\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write DSP code\n");
goto irl_error;
}
index += 2;
@@ -312,16 +316,16 @@ static int install_resident_loader(struct echoaudio *chip)
}
if (i == 200) {
- DE_INIT(("Resident loader failed to set HF5\n"));
+ dev_err(chip->card->dev, "Resident loader failed to set HF5\n");
goto irl_error;
}
- DE_INIT(("Resident loader successfully installed\n"));
- free_firmware(fw);
+ dev_dbg(chip->card->dev, "Resident loader successfully installed\n");
+ free_firmware(fw, chip);
return 0;
irl_error:
- free_firmware(fw);
+ free_firmware(fw, chip);
return -EIO;
}
@@ -334,14 +338,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
int index, words, i;
if (chip->dsp_code == code) {
- DE_INIT(("DSP is already loaded!\n"));
+ dev_warn(chip->card->dev, "DSP is already loaded!\n");
return 0;
}
chip->bad_board = TRUE; /* Set TRUE until DSP loaded */
chip->dsp_code = NULL; /* Current DSP code not loaded */
chip->asic_loaded = FALSE; /* Loading the DSP code will reset the ASIC */
- DE_INIT(("load_dsp: Set bad_board to TRUE\n"));
+ dev_dbg(chip->card->dev, "load_dsp: Set bad_board to TRUE\n");
/* If this board requires a resident loader, install it. */
#ifdef DSP_56361
@@ -351,7 +355,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
/* Send software reset command */
if (send_vector(chip, DSP_VC_RESET) < 0) {
- DE_INIT(("LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n"));
+ dev_err(chip->card->dev,
+ "LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n");
return -EIO;
}
/* Delay 10us */
@@ -366,7 +371,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
}
if (i == 1000) {
- DE_INIT(("load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n");
return -EIO;
}
@@ -403,29 +409,34 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
index += 2;
if (write_dsp(chip, words) < 0) {
- DE_INIT(("load_dsp: failed to write number of DSP words\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write number of DSP words\n");
return -EIO;
}
if (write_dsp(chip, address) < 0) {
- DE_INIT(("load_dsp: failed to write DSP address\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP address\n");
return -EIO;
}
if (write_dsp(chip, mem_type) < 0) {
- DE_INIT(("load_dsp: failed to write DSP memory type\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP memory type\n");
return -EIO;
}
/* Code */
for (i = 0; i < words; i++, index+=2) {
data = ((u32)code[index] << 16) + code[index + 1];
if (write_dsp(chip, data) < 0) {
- DE_INIT(("load_dsp: failed to write DSP data\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP data\n");
return -EIO;
}
}
}
if (write_dsp(chip, 0) < 0) { /* We're done!!! */
- DE_INIT(("load_dsp: Failed to write final zero\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write final zero\n");
return -EIO;
}
udelay(10);
@@ -438,12 +449,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00);
if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) {
- DE_INIT(("load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n");
return -EIO;
}
if (write_dsp(chip, chip->comm_page_phys) < 0) {
- DE_INIT(("load_dsp: Failed to write comm page address\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write comm page address\n");
return -EIO;
}
@@ -452,19 +465,20 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
We don't actually use the serial number but we have to
get it as part of the DSP init voodoo. */
if (read_sn(chip) < 0) {
- DE_INIT(("load_dsp: Failed to read serial number\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to read serial number\n");
return -EIO;
}
chip->dsp_code = code; /* Show which DSP code loaded */
chip->bad_board = FALSE; /* DSP OK */
- DE_INIT(("load_dsp: OK!\n"));
return 0;
}
udelay(100);
}
- DE_INIT(("load_dsp: DSP load timed out waiting for HF4\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: DSP load timed out waiting for HF4\n");
return -EIO;
}
@@ -491,7 +505,7 @@ static int load_firmware(struct echoaudio *chip)
if (err < 0)
return err;
err = load_dsp(chip, (u16 *)fw->data);
- free_firmware(fw);
+ free_firmware(fw, chip);
if (err < 0)
return err;
@@ -658,7 +672,6 @@ static void get_audio_meters(struct echoaudio *chip, long *meters)
static int restore_dsp_rettings(struct echoaudio *chip)
{
int i, o, err;
- DE_INIT(("restore_dsp_settings\n"));
if ((err = check_asic_status(chip)) < 0)
return err;
@@ -755,7 +768,6 @@ static int restore_dsp_rettings(struct echoaudio *chip)
if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0)
return -EIO;
- DE_INIT(("restore_dsp_rettings done\n"));
return 0;
}
@@ -835,7 +847,8 @@ static void set_audio_format(struct echoaudio *chip, u16 pipe_index,
break;
}
}
- DE_ACT(("set_audio_format[%d] = %x\n", pipe_index, dsp_format));
+ dev_dbg(chip->card->dev,
+ "set_audio_format[%d] = %x\n", pipe_index, dsp_format);
chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format);
}
@@ -848,7 +861,6 @@ Same thing for pause_ and stop_ -trasport below. */
static int start_transport(struct echoaudio *chip, u32 channel_mask,
u32 cyclic_mask)
{
- DE_ACT(("start_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -866,7 +878,7 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask,
return 0;
}
- DE_ACT(("start_transport: No pipes to start!\n"));
+ dev_err(chip->card->dev, "start_transport: No pipes to start!\n");
return -EINVAL;
}
@@ -874,7 +886,6 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask,
static int pause_transport(struct echoaudio *chip, u32 channel_mask)
{
- DE_ACT(("pause_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -893,7 +904,7 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask)
return 0;
}
- DE_ACT(("pause_transport: No pipes to stop!\n"));
+ dev_warn(chip->card->dev, "pause_transport: No pipes to stop!\n");
return 0;
}
@@ -901,7 +912,6 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask)
static int stop_transport(struct echoaudio *chip, u32 channel_mask)
{
- DE_ACT(("stop_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -920,7 +930,7 @@ static int stop_transport(struct echoaudio *chip, u32 channel_mask)
return 0;
}
- DE_ACT(("stop_transport: No pipes to stop!\n"));
+ dev_warn(chip->card->dev, "stop_transport: No pipes to stop!\n");
return 0;
}
@@ -937,7 +947,6 @@ static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index)
stopped and unallocated. */
static int rest_in_peace(struct echoaudio *chip)
{
- DE_ACT(("rest_in_peace() open=%x\n", chip->pipe_alloc_mask));
/* Stops all active pipes (just to be sure) */
stop_transport(chip, chip->active_mask);
@@ -965,7 +974,8 @@ static int init_dsp_comm_page(struct echoaudio *chip)
{
/* Check if the compiler added extra padding inside the structure */
if (offsetof(struct comm_page, midi_output) != 0xbe0) {
- DE_INIT(("init_dsp_comm_page() - Invalid struct comm_page structure\n"));
+ dev_err(chip->card->dev,
+ "init_dsp_comm_page() - Invalid struct comm_page structure\n");
return -EPERM;
}
@@ -999,7 +1009,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
*/
static int init_line_levels(struct echoaudio *chip)
{
- DE_INIT(("init_line_levels\n"));
memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain));
memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain));
memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain));
@@ -1051,7 +1060,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
u32 channel_mask;
char is_cyclic;
- DE_ACT(("allocate_pipes: ch=%d int=%d\n", pipe_index, interleave));
+ dev_dbg(chip->card->dev,
+ "allocate_pipes: ch=%d int=%d\n", pipe_index, interleave);
if (chip->bad_board)
return -EIO;
@@ -1061,7 +1071,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
for (channel_mask = i = 0; i < interleave; i++)
channel_mask |= 1 << (pipe_index + i);
if (chip->pipe_alloc_mask & channel_mask) {
- DE_ACT(("allocate_pipes: channel already open\n"));
+ dev_err(chip->card->dev,
+ "allocate_pipes: channel already open\n");
return -EAGAIN;
}
@@ -1078,7 +1089,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
it moves data. The DMA counter is in units of bytes, not samples. */
pipe->dma_counter = &chip->comm_page->position[pipe_index];
*pipe->dma_counter = 0;
- DE_ACT(("allocate_pipes: ok\n"));
return pipe_index;
}
@@ -1089,7 +1099,6 @@ static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe)
u32 channel_mask;
int i;
- DE_ACT(("free_pipes: Pipe %d\n", pipe->index));
if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index)))
return -EINVAL;
if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED))
@@ -1131,7 +1140,7 @@ static int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe,
list[head].size = cpu_to_le32(length);
pipe->sglist_head++;
} else {
- DE_ACT(("SGlist: too many fragments\n"));
+ dev_err(chip->card->dev, "SGlist: too many fragments\n");
return -ENOMEM;
}
return 0;
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
index afa273330e8a..23a099425834 100644
--- a/sound/pci/echoaudio/echoaudio_gml.c
+++ b/sound/pci/echoaudio/echoaudio_gml.c
@@ -46,7 +46,8 @@ static int check_asic_status(struct echoaudio *chip)
/* The DSP will return a value to indicate whether or not the
ASIC is currently loaded */
if (read_dsp(chip, &asic_status) < 0) {
- DE_INIT(("check_asic_status: failed on read_dsp\n"));
+ dev_err(chip->card->dev,
+ "check_asic_status: failed on read_dsp\n");
chip->asic_loaded = FALSE;
return -EIO;
}
@@ -68,7 +69,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force)
else
value &= ~GML_DIGITAL_IN_AUTO_MUTE;
- DE_ACT(("write_control_reg: 0x%x\n", value));
+ dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value);
/* Write the control register */
value = cpu_to_le32(value);
@@ -91,7 +92,7 @@ If the auto-mute is disabled, the digital inputs are enabled regardless of
what the input clock is set or what is connected. */
static int set_input_auto_mute(struct echoaudio *chip, int automute)
{
- DE_ACT(("set_input_auto_mute %d\n", automute));
+ dev_dbg(chip->card->dev, "set_input_auto_mute %d\n", automute);
chip->digital_in_automute = automute;
@@ -194,7 +195,7 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
if ((err = write_control_reg(chip, control_reg, FALSE)))
return err;
chip->professional_spdif = prof;
- DE_ACT(("set_professional_spdif to %s\n",
- prof ? "Professional" : "Consumer"));
+ dev_dbg(chip->card->dev, "set_professional_spdif to %s\n",
+ prof ? "Professional" : "Consumer");
return 0;
}
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
index d1615a0579d1..5dafe9260cb4 100644
--- a/sound/pci/echoaudio/gina20_dsp.c
+++ b/sound/pci/echoaudio/gina20_dsp.c
@@ -37,12 +37,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Gina20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -62,7 +62,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -149,7 +148,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
static int set_input_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_input_clock:\n"));
switch (clock) {
case ECHO_CLOCK_INTERNAL:
@@ -158,7 +156,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
set_sample_rate(chip, chip->sample_rate);
chip->input_clock = clock;
- DE_ACT(("Set Gina clock to INTERNAL\n"));
break;
case ECHO_CLOCK_SPDIF:
chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
@@ -166,7 +163,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
clear_handshake(chip);
send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
chip->clock_state = GD_CLOCK_SPDIFIN;
- DE_ACT(("Set Gina20 clock to SPDIF\n"));
chip->input_clock = clock;
break;
default:
@@ -208,7 +204,6 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
index 98f7cfa81b5f..6971766938bf 100644
--- a/sound/pci/echoaudio/gina24_dsp.c
+++ b/sound/pci/echoaudio/gina24_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Gina24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -78,7 +78,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -155,7 +154,6 @@ static int load_asic(struct echoaudio *chip)
control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
err = write_control_reg(chip, control_reg, TRUE);
}
- DE_INIT(("load_asic() done\n"));
return err;
}
@@ -171,8 +169,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -217,7 +215,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GML_8KHZ;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -225,7 +224,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev, "set_sample_rate: %d clock %d\n", rate, clock);
return write_control_reg(chip, control_reg, FALSE);
}
@@ -236,7 +235,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
{
u32 control_reg, clocks_from_dsp;
- DE_ACT(("set_input_clock:\n"));
/* Mask off the clock select bits */
control_reg = le32_to_cpu(chip->comm_page->control_register) &
@@ -245,13 +243,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Gina24 clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
if (chip->digital_mode == DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Gina24 clock to SPDIF\n"));
control_reg |= GML_SPDIF_CLOCK;
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= GML_DOUBLE_SPEED_MODE;
@@ -261,21 +257,19 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Gina24 clock to ADAT\n"));
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ESYNC:
- DE_ACT(("Set Gina24 clock to ESYNC\n"));
control_reg |= GML_ESYNC_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ESYNC96:
- DE_ACT(("Set Gina24 clock to ESYNC96\n"));
control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Gina24\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Gina24\n", clock);
return -EINVAL;
}
@@ -304,7 +298,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -344,6 +339,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", chip->digital_mode));
+ dev_dbg(chip->card->dev,
+ "set_digital_mode to %d\n", chip->digital_mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
index 5e85f14fe5a8..54edd67edff7 100644
--- a/sound/pci/echoaudio/indigo_dsp.c
+++ b/sound/pci/echoaudio/indigo_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -109,7 +108,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -147,7 +147,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c
index 2e4ab3e34a74..ceda2d7046ac 100644
--- a/sound/pci/echoaudio/indigo_express_dsp.c
+++ b/sound/pci/echoaudio/indigo_express_dsp.c
@@ -61,7 +61,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg |= clock;
if (control_reg != old_control_reg) {
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
chip->comm_page->control_register = cpu_to_le32(control_reg);
chip->sample_rate = rate;
clear_handshake(chip);
@@ -89,7 +90,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
index 68f3c8ccc1bf..2cf5cc092d7a 100644
--- a/sound/pci/echoaudio/indigodj_dsp.c
+++ b/sound/pci/echoaudio/indigodj_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo DJ\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -109,7 +108,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -147,7 +147,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c
index bb9632c752a9..5252863f1681 100644
--- a/sound/pci/echoaudio/indigodjx_dsp.c
+++ b/sound/pci/echoaudio/indigodjx_dsp.c
@@ -35,13 +35,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo DJx\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX))
return -ENODEV;
err = init_dsp_comm_page(chip);
if (err < 0) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -59,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
index beb9a5b69892..4e81787627e0 100644
--- a/sound/pci/echoaudio/indigoio_dsp.c
+++ b/sound/pci/echoaudio/indigoio_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo IO\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -118,7 +117,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c
index 394c6e76bcbc..6de3f9bc6d26 100644
--- a/sound/pci/echoaudio/indigoiox_dsp.c
+++ b/sound/pci/echoaudio/indigoiox_dsp.c
@@ -35,13 +35,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo IOx\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX))
return -ENODEV;
err = init_dsp_comm_page(chip);
if (err < 0) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -59,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
index 53ce94605044..f2024a3565af 100644
--- a/sound/pci/echoaudio/layla20_dsp.c
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -40,12 +40,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Layla20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -64,7 +64,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -121,7 +120,8 @@ static int check_asic_status(struct echoaudio *chip)
/* The DSP will return a value to indicate whether or not
the ASIC is currently loaded */
if (read_dsp(chip, &asic_status) < 0) {
- DE_ACT(("check_asic_status: failed on read_dsp\n"));
+ dev_err(chip->card->dev,
+ "check_asic_status: failed on read_dsp\n");
return -EIO;
}
@@ -164,8 +164,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. Do not return failure,
simply treat it as a non-event. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
return 0;
@@ -174,7 +174,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("set_sample_rate(%d)\n", rate));
+ dev_dbg(chip->card->dev, "set_sample_rate(%d)\n", rate);
chip->sample_rate = rate;
chip->comm_page->sample_rate = cpu_to_le32(rate);
clear_handshake(chip);
@@ -188,29 +188,25 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source)
u16 clock;
u32 rate;
- DE_ACT(("set_input_clock:\n"));
rate = 0;
switch (clock_source) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Layla20 clock to INTERNAL\n"));
rate = chip->sample_rate;
clock = LAYLA20_CLOCK_INTERNAL;
break;
case ECHO_CLOCK_SPDIF:
- DE_ACT(("Set Layla20 clock to SPDIF\n"));
clock = LAYLA20_CLOCK_SPDIF;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Layla20 clock to WORD\n"));
clock = LAYLA20_CLOCK_WORD;
break;
case ECHO_CLOCK_SUPER:
- DE_ACT(("Set Layla20 clock to SUPER\n"));
clock = LAYLA20_CLOCK_SUPER;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Layla24\n",
- clock_source));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Layla24\n",
+ clock_source);
return -EINVAL;
}
chip->input_clock = clock_source;
@@ -229,7 +225,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source)
static int set_output_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_output_clock: %d\n", clock));
switch (clock) {
case ECHO_CLOCK_SUPER:
clock = LAYLA20_OUTPUT_CLOCK_SUPER;
@@ -238,7 +233,7 @@ static int set_output_clock(struct echoaudio *chip, u16 clock)
clock = LAYLA20_OUTPUT_CLOCK_WORD;
break;
default:
- DE_ACT(("set_output_clock wrong clock\n"));
+ dev_err(chip->card->dev, "set_output_clock wrong clock\n");
return -EINVAL;
}
@@ -283,7 +278,6 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index 8c041647f285..4f11e81f6c0e 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -40,12 +40,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Layla24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -69,7 +69,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)) < 0)
return err;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -117,7 +116,6 @@ static int load_asic(struct echoaudio *chip)
if (chip->asic_loaded)
return 1;
- DE_INIT(("load_asic\n"));
/* Give the DSP a few milliseconds to settle down */
mdelay(10);
@@ -151,7 +149,6 @@ static int load_asic(struct echoaudio *chip)
err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ,
TRUE);
- DE_INIT(("load_asic() done\n"));
return err;
}
@@ -167,8 +164,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -241,7 +238,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP ? */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, control_reg));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, control_reg);
return write_control_reg(chip, control_reg, FALSE);
}
@@ -260,7 +258,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
/* Pick the new clock */
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Layla24 clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
@@ -269,7 +266,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg |= GML_SPDIF_CLOCK;
/* Layla24 doesn't support 96KHz S/PDIF */
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to SPDIF\n"));
break;
case ECHO_CLOCK_WORD:
control_reg |= GML_WORD_CLOCK;
@@ -277,17 +273,16 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg |= GML_DOUBLE_SPEED_MODE;
else
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to WORD\n"));
break;
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to ADAT\n"));
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Layla24\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Layla24\n", clock);
return -EINVAL;
}
@@ -353,7 +348,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
asic = FW_LAYLA24_2A_ASIC;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -393,6 +389,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", mode));
+ dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
index 6ebfa6e7ab9e..fdad079ad9a1 100644
--- a/sound/pci/echoaudio/mia_dsp.c
+++ b/sound/pci/echoaudio/mia_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Mia\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -66,7 +66,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -126,7 +125,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -153,7 +153,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
static int set_input_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_input_clock(%d)\n", clock));
+ dev_dbg(chip->card->dev, "set_input_clock(%d)\n", clock);
if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
clock != ECHO_CLOCK_SPDIF))
return -EINVAL;
@@ -181,7 +181,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
@@ -211,7 +212,7 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
+ dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof);
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 7f4dfae0323a..d913749d154a 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -36,7 +36,7 @@
/* Start and stop Midi input */
static int enable_midi_input(struct echoaudio *chip, char enable)
{
- DE_MID(("enable_midi_input(%d)\n", enable));
+ dev_dbg(chip->card->dev, "enable_midi_input(%d)\n", enable);
if (wait_handshake(chip))
return -EIO;
@@ -74,7 +74,7 @@ static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
chip->comm_page->midi_out_free_count = 0;
clear_handshake(chip);
send_vector(chip, DSP_VC_MIDI_WRITE);
- DE_MID(("write_midi: %d\n", bytes));
+ dev_dbg(chip->card->dev, "write_midi: %d\n", bytes);
return bytes;
}
@@ -157,7 +157,6 @@ static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_in = substream;
- DE_MID(("rawmidi_iopen\n"));
return 0;
}
@@ -183,7 +182,6 @@ static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_in = NULL;
- DE_MID(("rawmidi_iclose\n"));
return 0;
}
@@ -196,7 +194,6 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
chip->tinuse = 0;
chip->midi_full = 0;
chip->midi_out = substream;
- DE_MID(("rawmidi_oopen\n"));
return 0;
}
@@ -209,7 +206,6 @@ static void snd_echo_midi_output_write(unsigned long data)
int bytes, sent, time;
unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
- DE_MID(("snd_echo_midi_output_write\n"));
/* No interrupts are involved: we have to check at regular intervals
if the card's output buffer has room for new data. */
sent = bytes = 0;
@@ -218,7 +214,7 @@ static void snd_echo_midi_output_write(unsigned long data)
if (!snd_rawmidi_transmit_empty(chip->midi_out)) {
bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
MIDI_OUT_BUFFER_SIZE - 1);
- DE_MID(("Try to send %d bytes...\n", bytes));
+ dev_dbg(chip->card->dev, "Try to send %d bytes...\n", bytes);
sent = write_midi(chip, buf, bytes);
if (sent < 0) {
dev_err(chip->card->dev,
@@ -227,12 +223,12 @@ static void snd_echo_midi_output_write(unsigned long data)
sent = 9000;
chip->midi_full = 1;
} else if (sent > 0) {
- DE_MID(("%d bytes sent\n", sent));
+ dev_dbg(chip->card->dev, "%d bytes sent\n", sent);
snd_rawmidi_transmit_ack(chip->midi_out, sent);
} else {
/* Buffer is full. DSP's internal buffer is 64 (128 ?)
bytes long. Let's wait until half of them are sent */
- DE_MID(("Full\n"));
+ dev_dbg(chip->card->dev, "Full\n");
sent = 32;
chip->midi_full = 1;
}
@@ -244,7 +240,8 @@ static void snd_echo_midi_output_write(unsigned long data)
sent */
time = (sent << 3) / 25 + 1; /* 8/25=0.32ms to send a byte */
mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
- DE_MID(("Timer armed(%d)\n", ((time * HZ + 999) / 1000)));
+ dev_dbg(chip->card->dev,
+ "Timer armed(%d)\n", ((time * HZ + 999) / 1000));
}
spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -256,7 +253,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
{
struct echoaudio *chip = substream->rmidi->private_data;
- DE_MID(("snd_echo_midi_output_trigger(%d)\n", up));
+ dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up);
spin_lock_irq(&chip->lock);
if (up) {
if (!chip->tinuse) {
@@ -270,7 +267,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
chip->tinuse = 0;
spin_unlock_irq(&chip->lock);
del_timer_sync(&chip->timer);
- DE_MID(("Timer removed\n"));
+ dev_dbg(chip->card->dev, "Timer removed\n");
return;
}
}
@@ -287,7 +284,6 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_out = NULL;
- DE_MID(("rawmidi_oclose\n"));
return 0;
}
@@ -327,6 +323,5 @@ static int snd_echo_midi_create(struct snd_card *card,
chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
- DE_INIT(("MIDI ok\n"));
return 0;
}
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
index 6e6a7eb555b8..843c7a5e5105 100644
--- a/sound/pci/echoaudio/mona_dsp.c
+++ b/sound/pci/echoaudio/mona_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Mona\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -71,7 +71,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -202,8 +201,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_dbg(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -279,7 +278,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GML_8KHZ;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -287,7 +287,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
return write_control_reg(chip, control_reg, force_write);
}
@@ -299,7 +300,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
u32 control_reg, clocks_from_dsp;
int err;
- DE_ACT(("set_input_clock:\n"));
/* Prevent two simultaneous calls to switch_asic() */
if (atomic_read(&chip->opencount))
@@ -312,7 +312,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Mona clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
@@ -324,7 +323,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
spin_lock_irq(&chip->lock);
if (err < 0)
return err;
- DE_ACT(("Set Mona clock to SPDIF\n"));
control_reg |= GML_SPDIF_CLOCK;
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= GML_DOUBLE_SPEED_MODE;
@@ -332,7 +330,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Mona clock to WORD\n"));
spin_unlock_irq(&chip->lock);
err = switch_asic(chip, clocks_from_dsp &
GML_CLOCK_DETECT_BIT_WORD96);
@@ -346,14 +343,15 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ADAT:
- DE_ACT(("Set Mona clock to ADAT\n"));
+ dev_dbg(chip->card->dev, "Set Mona clock to ADAT\n");
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Mona\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Mona\n", clock);
return -EINVAL;
}
@@ -381,7 +379,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -422,6 +421,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", mode));
+ dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode);
return incompatible_clock;
}
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 229269788023..b4458a630a7c 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1289,10 +1289,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
}
if (emu->emu1010.firmware_thread)
kthread_stop(emu->emu1010.firmware_thread);
- if (emu->firmware)
- release_firmware(emu->firmware);
- if (emu->dock_fw)
- release_firmware(emu->dock_fw);
+ release_firmware(emu->firmware);
+ release_firmware(emu->dock_fw);
if (emu->irq >= 0)
free_irq(emu->irq, emu);
/* remove reserved page */
@@ -1301,8 +1299,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
(struct snd_util_memblk *)emu->reserved_page);
emu->reserved_page = NULL;
}
- if (emu->memhdr)
- snd_util_memhdr_free(emu->memhdr);
+ snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
snd_dma_free_pages(&emu->silent_page);
if (emu->ptb_pages.area)
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index e223de1408c0..15933f92f63a 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -180,7 +180,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
/* From 0x50 - 0x5f, last samples captured */
-/**
+/*
* The hardware has 3 channels for playback and 1 for capture.
* - channel 0 is the front channel
* - channel 1 is the rear channel
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 745f0627c634..eb5c0aba41c1 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -777,8 +777,7 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
kctl->private_value = 0;
list_del(&ctl->list);
kfree(ctl);
- if (kctl->tlv.p)
- kfree(kctl->tlv.p);
+ kfree(kctl->tlv.p);
}
static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index c5ae2a24d8a5..1de33025669a 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -83,7 +83,7 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
* Items labels in enum mixer controls assigning source data to
* each destination
*/
-static char *emu1010_src_texts[] = {
+static const char * const emu1010_src_texts[] = {
"Silence",
"Dock Mic A",
"Dock Mic B",
@@ -141,7 +141,7 @@ static char *emu1010_src_texts[] = {
/* 1616(m) cardbus */
-static char *emu1616_src_texts[] = {
+static const char * const emu1616_src_texts[] = {
"Silence",
"Dock Mic A",
"Dock Mic B",
@@ -393,23 +393,11 @@ 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);
- char **items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
- uinfo->value.enumerated.items = 49;
- items = emu1616_src_texts;
- } else {
- uinfo->value.enumerated.items = 53;
- items = emu1010_src_texts;
- }
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- items[uinfo->value.enumerated.item]);
- return 0;
+ 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);
}
static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
@@ -699,19 +687,11 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"44100", "48000", "SPDIF", "ADAT"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-
-
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
@@ -830,21 +810,15 @@ static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
#if 0
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Unknown1", "Unknown2", "Mic", "Line"
};
#endif
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Mic", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -997,15 +971,9 @@ static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
#if 0
static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"44100", "48000", "96000"};
+ static const char * const texts[] = {"44100", "48000", "96000"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index a4fe7f0c9458..7ef3898a7806 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -757,18 +757,12 @@ static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol,
static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S",
"CDIF", "FX", "AC97"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -805,15 +799,9 @@ static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "0", "1", "2", "3", };
+ static const char * const texts[4] = { "0", "1", "2", "3", };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 639962443ccc..0fc46eb4e251 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1045,18 +1045,12 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device)
static int snd_es1938_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_es1938_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a9956a7c5677..6039700f8579 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1710,7 +1710,8 @@ static void es1968_measure_clock(struct es1968 *chip)
int i, apu;
unsigned int pa, offset, t;
struct esm_memory *memory;
- struct timeval start_time, stop_time;
+ ktime_t start_time, stop_time;
+ ktime_t diff;
if (chip->clock == 0)
chip->clock = 48000; /* default clock value */
@@ -1761,12 +1762,12 @@ static void es1968_measure_clock(struct es1968 *chip)
snd_es1968_bob_inc(chip, ESM_BOB_FREQ);
__apu_set_register(chip, apu, 5, pa & 0xffff);
snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
- do_gettimeofday(&start_time);
+ start_time = ktime_get();
spin_unlock_irq(&chip->reg_lock);
msleep(50);
spin_lock_irq(&chip->reg_lock);
offset = __apu_get_register(chip, apu, 5);
- do_gettimeofday(&stop_time);
+ stop_time = ktime_get();
snd_es1968_trigger_apu(chip, apu, 0); /* stop */
snd_es1968_bob_dec(chip);
chip->in_measurement = 0;
@@ -1777,12 +1778,8 @@ static void es1968_measure_clock(struct es1968 *chip)
offset &= 0xfffe;
offset += chip->measure_count * (CLOCK_MEASURE_BUFSIZE/2);
- t = stop_time.tv_sec - start_time.tv_sec;
- t *= 1000000;
- if (stop_time.tv_usec < start_time.tv_usec)
- t -= start_time.tv_usec - stop_time.tv_usec;
- else
- t += stop_time.tv_usec - start_time.tv_usec;
+ diff = ktime_sub(stop_time, start_time);
+ t = ktime_to_us(diff);
if (t == 0) {
dev_err(chip->card->dev, "?? calculation error..\n");
} else {
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index c5038303a126..d167afffce5f 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -958,17 +958,11 @@ static int snd_fm801_put_double(struct snd_kcontrol *kcontrol,
static int snd_fm801_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = {
+ static const char * const texts[5] = {
"AC97 Primary", "FM", "I2S", "PCM", "AC97 Secondary"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index fcc5e478c9a1..1ede82200ee5 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -441,6 +441,13 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg);
+/**
+ * snd_hda_get_input_pin_attr - Get the input pin attribute from pin config
+ * @def_conf: pin configuration value
+ *
+ * Guess the input pin attribute (INPUT_PIN_ATTR_XXX) from the given
+ * default pin configuration value.
+ */
int snd_hda_get_input_pin_attr(unsigned int def_conf)
{
unsigned int loc = get_defcfg_location(def_conf);
@@ -464,12 +471,15 @@ EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr);
/**
* hda_get_input_pin_label - Give a label for the given input pin
+ * @codec: the HDA codec
+ * @item: ping config item to refer
+ * @pin: the pin NID
+ * @check_location: flag to add the jack location prefix
*
- * When check_location is true, the function checks the pin location
+ * When @check_location is true, the function checks the pin location
* for mic and line-in pins, and set an appropriate prefix like "Front",
* "Rear", "Internal".
*/
-
static const char *hda_get_input_pin_label(struct hda_codec *codec,
const struct auto_pin_cfg_item *item,
hda_nid_t pin, bool check_location)
@@ -550,6 +560,9 @@ static int check_mic_location_need(struct hda_codec *codec,
/**
* hda_get_autocfg_input_label - Get a label for the given input
+ * @codec: the HDA codec
+ * @cfg: the parsed pin configuration
+ * @input: the input index number
*
* Get a label for the given input pin defined by the autocfg item.
* Unlike hda_get_input_pin_label(), this function checks all inputs
@@ -677,6 +690,12 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @cfg: the parsed pin configuration
+ * @label: the string buffer to store
+ * @maxlen: the max length of string buffer (including termination)
+ * @indexp: the pointer to return the index number (for multiple ctls)
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
@@ -748,6 +767,14 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_get_pin_label);
+/**
+ * snd_hda_add_verbs - Add verbs to the init list
+ * @codec: the HDA codec
+ * @list: zero-terminated verb list to add
+ *
+ * Append the given verb list to the execution list. The verbs will be
+ * performed at init and resume time via snd_hda_apply_verbs().
+ */
int snd_hda_add_verbs(struct hda_codec *codec,
const struct hda_verb *list)
{
@@ -760,6 +787,10 @@ int snd_hda_add_verbs(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_add_verbs);
+/**
+ * snd_hda_apply_verbs - Execute the init verb lists
+ * @codec: the HDA codec
+ */
void snd_hda_apply_verbs(struct hda_codec *codec)
{
int i;
@@ -770,6 +801,11 @@ void snd_hda_apply_verbs(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_apply_verbs);
+/**
+ * snd_hda_apply_pincfgs - Set each pin config in the given list
+ * @codec: the HDA codec
+ * @cfg: NULL-terminated pin config table
+ */
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg)
{
@@ -837,6 +873,11 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
}
}
+/**
+ * snd_hda_apply_fixup - Apply the fixup chain with the given action
+ * @codec: the HDA codec
+ * @action: fixup action (HDA_FIXUP_ACT_XXX)
+ */
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
{
if (codec->fixup_list)
@@ -855,6 +896,12 @@ static bool pin_config_match(struct hda_codec *codec,
return true;
}
+/**
+ * snd_hda_pick_pin_fixup - Pick up a fixup matching with the pin quirk list
+ * @codec: the HDA codec
+ * @pin_quirk: zero-terminated pin quirk list
+ * @fixlist: the fixup list
+ */
void snd_hda_pick_pin_fixup(struct hda_codec *codec,
const struct snd_hda_pin_quirk *pin_quirk,
const struct hda_fixup *fixlist)
@@ -881,6 +928,21 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
+/**
+ * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string
+ * @codec: the HDA codec
+ * @models: NULL-terminated model string list
+ * @quirk: zero-terminated PCI/codec SSID quirk list
+ * @fixlist: the fixup list
+ *
+ * Pick up a fixup entry matching with the given model string or SSID.
+ * If a fixup was already set beforehand, the function doesn't do anything.
+ * When a special model string "nofixup" is given, also no fixup is applied.
+ *
+ * The function tries to find the matching model name at first, if given.
+ * If nothing matched, try to look up the PCI SSID.
+ * If still nothing matched, try to look up the codec SSID.
+ */
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 8c6c50afc0b7..1e7de08e77cb 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -175,6 +175,11 @@ static int snd_hda_do_attach(struct hda_beep *beep)
return 0;
}
+/**
+ * snd_hda_enable_beep_device - Turn on/off beep sound
+ * @codec: the HDA codec
+ * @enable: flag to turn on/off
+ */
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
{
struct hda_beep *beep = codec->beep;
@@ -191,6 +196,20 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
}
EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device);
+/**
+ * snd_hda_attach_beep_device - Attach a beep input device
+ * @codec: the HDA codec
+ * @nid: beep NID
+ *
+ * Attach a beep object to the given widget. If beep hint is turned off
+ * explicitly or beep_mode of the codec is turned off, this doesn't nothing.
+ *
+ * The attached beep device has to be registered via
+ * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device()
+ * appropriately.
+ *
+ * Currently, only one beep device is allowed to each codec.
+ */
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
{
struct hda_beep *beep;
@@ -228,6 +247,10 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
}
EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device);
+/**
+ * snd_hda_detach_beep_device - Detach the beep device
+ * @codec: the HDA codec
+ */
void snd_hda_detach_beep_device(struct hda_codec *codec)
{
struct hda_beep *beep = codec->beep;
@@ -240,6 +263,10 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
+/**
+ * snd_hda_register_beep_device - Register the beep device
+ * @codec: the HDA codec
+ */
int snd_hda_register_beep_device(struct hda_codec *codec)
{
struct hda_beep *beep = codec->beep;
@@ -269,6 +296,12 @@ static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
}
/* get/put callbacks for beep mute mixer switches */
+
+/**
+ * snd_hda_mixer_amp_switch_get_beep - Get callback for beep controls
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
+ */
int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -283,6 +316,11 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep);
+/**
+ * snd_hda_mixer_amp_switch_put_beep - Put callback for beep controls
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
+ */
int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 15e0089492f7..2fe86d2e1b09 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -77,6 +77,10 @@ static struct hda_vendor_id hda_vendor_ids[] = {
static DEFINE_MUTEX(preset_mutex);
static LIST_HEAD(hda_preset_tables);
+/**
+ * snd_hda_add_codec_preset - Add a codec preset to the chain
+ * @preset: codec preset table to add
+ */
int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
{
mutex_lock(&preset_mutex);
@@ -86,6 +90,10 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
}
EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
+/**
+ * snd_hda_delete_codec_preset - Delete a codec preset from the chain
+ * @preset: codec preset table to delete
+ */
int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
{
mutex_lock(&preset_mutex);
@@ -338,8 +346,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
- if (parm == -1)
+ if (parm == -1) {
+ *start_id = 0;
return 0;
+ }
*start_id = (parm >> 16) & 0x7fff;
return (int)(parm & 0x7fff);
}
@@ -416,7 +426,6 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
* snd_hda_get_conn_list - get connection list
* @codec: the HDA codec
* @nid: NID to parse
- * @len: number of connection list entries
* @listp: the pointer to store NID list
*
* Parses the connection list of the given widget and stores the pointer
@@ -827,8 +836,7 @@ static void snd_hda_bus_free(struct hda_bus *bus)
WARN_ON(!list_empty(&bus->codec_list));
if (bus->workq)
flush_workqueue(bus->workq);
- if (bus->unsol)
- kfree(bus->unsol);
+ kfree(bus->unsol);
if (bus->ops.private_free)
bus->ops.private_free(bus);
if (bus->workq)
@@ -966,14 +974,12 @@ find_codec_preset(struct hda_codec *codec)
mutex_unlock(&preset_mutex);
if (mod_requested < HDA_MODREQ_MAX_COUNT) {
- char name[32];
if (!mod_requested)
- snprintf(name, sizeof(name), "snd-hda-codec-id:%08x",
- codec->vendor_id);
+ request_module("snd-hda-codec-id:%08x",
+ codec->vendor_id);
else
- snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*",
- (codec->vendor_id >> 16) & 0xffff);
- request_module(name);
+ request_module("snd-hda-codec-id:%04x*",
+ (codec->vendor_id >> 16) & 0xffff);
mod_requested++;
goto again;
}
@@ -1190,7 +1196,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
}
EXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg);
-/* remember the current pinctl target value */
+/**
+ * snd_hda_codec_set_pin_target - remember the current pinctl target value
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @val: assigned pinctl value
+ *
+ * This function stores the given value to a pinctl target value in the
+ * pincfg table. This isn't always as same as the actually written value
+ * but can be referred at any time via snd_hda_codec_get_pin_target().
+ */
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
unsigned int val)
{
@@ -1204,7 +1219,11 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target);
-/* return the current pinctl target value */
+/**
+ * snd_hda_codec_get_pin_target - return the current pinctl target value
+ * @codec: the HDA codec
+ * @nid: pin NID
+ */
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_pincfg *pin;
@@ -1576,6 +1595,13 @@ int snd_hda_codec_new(struct hda_bus *bus,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+/**
+ * snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
+ * @codec: the HDA codec
+ *
+ * Forcibly refresh the all widget caps and the init pin configurations of
+ * the given codec.
+ */
int snd_hda_codec_update_widgets(struct hda_codec *codec)
{
hda_nid_t fg;
@@ -2006,6 +2032,7 @@ EXPORT_SYMBOL_GPL(query_amp_caps);
* @codec: the HD-audio codec
* @nid: the NID to query
* @dir: either #HDA_INPUT or #HDA_OUTPUT
+ * @bits: bit mask to check the result
*
* Check whether the widget has the given amp capability for the direction.
*/
@@ -2025,7 +2052,7 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
* snd_hda_override_amp_caps - Override the AMP capabilities
* @codec: the CODEC to clean up
* @nid: the NID to clean up
- * @direction: either #HDA_INPUT or #HDA_OUTPUT
+ * @dir: either #HDA_INPUT or #HDA_OUTPUT
* @caps: the capability bits to set
*
* Override the cached AMP caps bits value by the given one.
@@ -2241,7 +2268,17 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
-/* Works like snd_hda_codec_amp_update() but it writes the value only at
+/**
+ * snd_hda_codec_amp_init - initialize the AMP value
+ * @codec: the HDA codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Works like snd_hda_codec_amp_update() but it writes the value only at
* the first access. If the amp was already initialized / updated beforehand,
* this does nothing.
*/
@@ -2252,6 +2289,17 @@ int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
+/**
+ * snd_hda_codec_amp_init_stereo - initialize the stereo AMP value
+ * @codec: the HDA codec
+ * @nid: NID to read the AMP value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Call snd_hda_codec_amp_init() for both stereo channels.
+ */
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val)
{
@@ -2322,6 +2370,8 @@ static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
/**
* snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2383,6 +2433,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2408,6 +2460,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get);
/**
* snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2438,6 +2492,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
/**
* snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @op_flag: operation flag
+ * @size: byte size of input TLV
+ * @_tlv: TLV data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2636,7 +2694,10 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
snd_array_free(&codec->nids);
}
-/* pseudo device locking
+/**
+ * snd_hda_lock_devices - pseudo device locking
+ * @bus: the BUS
+ *
* toggle card->shutdown to allow/disallow the device access (as a hack)
*/
int snd_hda_lock_devices(struct hda_bus *bus)
@@ -2673,6 +2734,10 @@ int snd_hda_lock_devices(struct hda_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hda_lock_devices);
+/**
+ * snd_hda_unlock_devices - pseudo device unlocking
+ * @bus: the BUS
+ */
void snd_hda_unlock_devices(struct hda_bus *bus)
{
struct snd_card *card = bus->card;
@@ -2859,7 +2924,7 @@ static int add_slave(struct hda_codec *codec,
}
/**
- * snd_hda_add_vmaster - create a virtual master control and add slaves
+ * __snd_hda_add_vmaster - create a virtual master control and add slaves
* @codec: HD-audio codec
* @name: vmaster control name
* @tlv: TLV data (optional)
@@ -2927,16 +2992,8 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
static const char * const texts[] = {
"On", "Off", "Follow Master"
};
- unsigned int index;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- index = uinfo->value.enumerated.item;
- if (index >= 3)
- index = 2;
- strcpy(uinfo->value.enumerated.name, texts[index]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
@@ -2970,10 +3027,15 @@ static struct snd_kcontrol_new vmaster_mute_mode = {
.put = vmaster_mute_mode_put,
};
-/*
- * Add a mute-LED hook with the given vmaster switch kctl
- * "Mute-LED Mode" control is automatically created and associated with
- * the given hook.
+/**
+ * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
+ * @codec: the HDA codec
+ * @hook: the vmaster hook object
+ * @expose_enum_ctl: flag to create an enum ctl
+ *
+ * Add a mute-LED hook with the given vmaster switch kctl.
+ * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically
+ * created and associated with the given hook.
*/
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
@@ -2995,9 +3057,12 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
-/*
- * Call the hook with the current value for synchronization
- * Should be called in init callback
+/**
+ * snd_hda_sync_vmaster_hook - Sync vmaster hook
+ * @hook: the vmaster hook
+ *
+ * Call the hook with the current value for synchronization.
+ * Should be called in init callback.
*/
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
{
@@ -3022,6 +3087,8 @@ EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook);
/**
* snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3041,6 +3108,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info);
/**
* snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3067,6 +3136,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get);
/**
* snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3110,6 +3181,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
/**
* snd_hda_mixer_bind_switch_get - Get callback for a bound volume control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_MUTE*() macros.
@@ -3133,6 +3206,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get);
/**
* snd_hda_mixer_bind_switch_put - Put callback for a bound volume control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_MUTE*() macros.
@@ -3163,6 +3238,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put);
/**
* snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3186,6 +3263,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info);
/**
* snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3209,6 +3288,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get);
/**
* snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3238,6 +3319,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put);
/**
* snd_hda_mixer_bind_tlv - TLV callback for a generic bound control
+ * @kcontrol: ctl element
+ * @op_flag: operation flag
+ * @size: byte size of input TLV
+ * @tlv: TLV data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() macro.
@@ -3579,7 +3664,11 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls);
-/* get the hda_spdif_out entry from the given NID
+/**
+ * snd_hda_spdif_out_of_nid - get the hda_spdif_out entry from the given NID
+ * @codec: the HDA codec
+ * @nid: widget NID
+ *
* call within spdif_mutex lock
*/
struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
@@ -3596,6 +3685,13 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid);
+/**
+ * snd_hda_spdif_ctls_unassign - Unassign the given SPDIF ctl
+ * @codec: the HDA codec
+ * @idx: the SPDIF ctl index
+ *
+ * Unassign the widget from the given SPDIF control.
+ */
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
{
struct hda_spdif_out *spdif;
@@ -3607,6 +3703,14 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign);
+/**
+ * snd_hda_spdif_ctls_assign - Assign the SPDIF controls to the given NID
+ * @codec: the HDA codec
+ * @idx: the SPDIF ctl idx
+ * @nid: widget NID
+ *
+ * Assign the widget to the SPDIF control with the given index.
+ */
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
{
struct hda_spdif_out *spdif;
@@ -3926,6 +4030,16 @@ void snd_hda_codec_flush_cache(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache);
+/**
+ * snd_hda_codec_set_power_to_all - Set the power state to all widgets
+ * @codec: the HDA codec
+ * @fg: function group (not used now)
+ * @power_state: the power state to set (AC_PWRST_*)
+ *
+ * Set the given power state to all widgets that have the power control.
+ * If the codec has power_filter set, it evaluates the power state and
+ * filter out if it's unchanged as D3.
+ */
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state)
{
@@ -3990,7 +4104,15 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
return state;
}
-/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */
+/**
+ * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
+ * @codec: the HDA codec
+ * @nid: widget NID
+ * @power_state: power state to evalue
+ *
+ * Don't power down the widget if it controls eapd and EAPD_BTLENABLE is set.
+ * This can be used a codec power_filter callback.
+ */
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
@@ -4315,6 +4437,7 @@ static struct hda_rate_tbl rate_bits[] = {
* @channels: the number of channels
* @format: the PCM format (SNDRV_PCM_FORMAT_XXX)
* @maxbps: the max. bps
+ * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant)
*
* Calculate the format bitset from the given rate, channels and th PCM format.
*
@@ -4650,6 +4773,17 @@ static int set_pcm_default_values(struct hda_codec *codec,
/*
* codec prepare/cleanup entries
*/
+/**
+ * snd_hda_codec_prepare - Prepare a stream
+ * @codec: the HDA codec
+ * @hinfo: PCM information
+ * @stream: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
+ *
+ * Calls the prepare callback set by the codec with the given arguments.
+ * Clean up the inactive streams when successful.
+ */
int snd_hda_codec_prepare(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
unsigned int stream,
@@ -4666,6 +4800,14 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_prepare);
+/**
+ * snd_hda_codec_cleanup - Prepare a stream
+ * @codec: the HDA codec
+ * @hinfo: PCM information
+ * @substream: PCM substream
+ *
+ * Calls the cleanup callback set by the codec with the given arguments.
+ */
void snd_hda_codec_cleanup(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
@@ -4990,6 +5132,7 @@ static void __snd_hda_power_down(struct hda_codec *codec)
* snd_hda_power_save - Power-up/down/sync the codec
* @codec: HD-audio codec
* @delta: the counter delta to change
+ * @d3wait: sync for D3 transition complete
*
* Change the power-up counter via @delta, and power up or down the hardware
* appropriately. For the power-down, queue to the delayed action.
@@ -5065,6 +5208,10 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
/**
* snd_hda_ch_mode_info - Info callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @uinfo: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
*/
int snd_hda_ch_mode_info(struct hda_codec *codec,
struct snd_ctl_elem_info *uinfo,
@@ -5084,6 +5231,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
/**
* snd_hda_ch_mode_get - Get callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @ucontrol: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
+ * @max_channels: max number of channels
*/
int snd_hda_ch_mode_get(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -5105,6 +5257,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
/**
* snd_hda_ch_mode_put - Put callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @ucontrol: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
+ * @max_channelsp: pointer to store the max channels
*/
int snd_hda_ch_mode_put(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -5133,6 +5290,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
/**
* snd_hda_input_mux_info_info - Info callback helper for the input-mux enum
+ * @imux: imux helper object
+ * @uinfo: pointer to get/store the data
*/
int snd_hda_input_mux_info(const struct hda_input_mux *imux,
struct snd_ctl_elem_info *uinfo)
@@ -5154,6 +5313,11 @@ EXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
/**
* snd_hda_input_mux_info_put - Put callback helper for the input-mux enum
+ * @codec: the HDA codec
+ * @imux: imux helper object
+ * @ucontrol: pointer to get/store the data
+ * @nid: input mux NID
+ * @cur_val: pointer to get/store the current imux value
*/
int snd_hda_input_mux_put(struct hda_codec *codec,
const struct hda_input_mux *imux,
@@ -5178,7 +5342,13 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
EXPORT_SYMBOL_GPL(snd_hda_input_mux_put);
-/*
+/**
+ * snd_hda_enum_helper_info - Helper for simple enum ctls
+ * @kcontrol: ctl element
+ * @uinfo: pointer to get/store the data
+ * @num_items: number of enum items
+ * @texts: enum item string array
+ *
* process kcontrol info callback of a simple string enum array
* when @num_items is 0 or @texts is NULL, assume a boolean enum array
*/
@@ -5195,14 +5365,7 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
texts = texts_default;
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_items;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
EXPORT_SYMBOL_GPL(snd_hda_enum_helper_info);
@@ -5274,6 +5437,8 @@ EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
/**
* snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_open(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5290,6 +5455,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
/**
* snd_hda_multi_out_dig_prepare - prepare the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @stream_tag: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
*/
int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
struct hda_multi_out *mout,
@@ -5306,6 +5476,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
/**
* snd_hda_multi_out_dig_cleanup - clean-up the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5319,6 +5491,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
/**
* snd_hda_multi_out_dig_close - release the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_close(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5332,6 +5506,10 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
/**
* snd_hda_multi_out_analog_open - open analog outputs
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @substream: PCM substream to assign
+ * @hinfo: PCM information to assign
*
* Open analog outputs and set up the hw-constraints.
* If the digital outputs can be opened as slave, open the digital
@@ -5382,6 +5560,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open);
/**
* snd_hda_multi_out_analog_prepare - Preapre the analog outputs.
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @stream_tag: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
*
* Set up the i/o for analog out.
* When the digital out is available, copy the front out to digital out, too.
@@ -5459,6 +5642,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare);
/**
* snd_hda_multi_out_analog_cleanup - clean up the setting for analog out
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5490,6 +5675,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
/**
* snd_hda_get_default_vref - Get the default (mic) VREF pin bits
+ * @codec: the HDA codec
+ * @pin: referred pin NID
*
* Guess the suitable VREF pin bits to be set as the pin-control value.
* Note: the function doesn't set the AC_PINCTL_IN_EN bit.
@@ -5515,7 +5702,12 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
}
EXPORT_SYMBOL_GPL(snd_hda_get_default_vref);
-/* correct the pin ctl value for matching with the pin cap */
+/**
+ * snd_hda_correct_pin_ctl - correct the pin ctl value for matching with the pin cap
+ * @codec: the HDA codec
+ * @pin: referred pin NID
+ * @val: pin ctl value to audit
+ */
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
hda_nid_t pin, unsigned int val)
{
@@ -5566,6 +5758,19 @@ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
+/**
+ * _snd_hda_pin_ctl - Helper to set pin ctl value
+ * @codec: the HDA codec
+ * @pin: referred pin NID
+ * @val: pin control value to set
+ * @cached: access over codec pinctl cache or direct write
+ *
+ * This function is a helper to set a pin ctl value more safely.
+ * It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the
+ * value in pin target array via snd_hda_codec_set_pin_target(), then
+ * actually writes the value via either snd_hda_codec_update_cache() or
+ * snd_hda_codec_write() depending on @cached flag.
+ */
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
unsigned int val, bool cached)
{
@@ -5582,6 +5787,11 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl);
/**
* snd_hda_add_imux_item - Add an item to input_mux
+ * @codec: the HDA codec
+ * @imux: imux helper object
+ * @label: the name of imux item to assign
+ * @index: index number of imux item to assign
+ * @type_idx: pointer to store the resultant label index
*
* When the same label is used already in the existing items, the number
* suffix is appended to the label. This label index number is stored
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index e1cd34d9011d..0e6d7534f491 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -371,7 +371,7 @@ error:
return ret;
}
-/**
+/*
* SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with
* hdmi-specific routine.
*/
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 64220c08bd98..b680b4ec6331 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -40,7 +40,12 @@
#include "hda_generic.h"
-/* initialize hda_gen_spec struct */
+/**
+ * snd_hda_gen_spec_init - initialize hda_gen_spec struct
+ * @spec: hda_gen_spec object to initialize
+ *
+ * Initialize the given hda_gen_spec object.
+ */
int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
{
snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
@@ -51,6 +56,17 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
+/**
+ * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
+ * @spec: hda_gen_spec object
+ * @name: name string to override the template, NULL if unchanged
+ * @temp: template for the new kctl
+ *
+ * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
+ * element based on the given snd_kcontrol_new template @temp and the
+ * name string @name to the list in @spec.
+ * Returns the newly created object or NULL as error.
+ */
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
const struct snd_kcontrol_new *temp)
@@ -259,8 +275,14 @@ static struct nid_path *get_nid_path(struct hda_codec *codec,
return NULL;
}
-/* get the path between the given NIDs;
- * passing 0 to either @pin or @dac behaves as a wildcard
+/**
+ * snd_hda_get_nid_path - get the path between the given NIDs
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ *
+ * Return the found nid_path object or NULL for error.
+ * Passing 0 to either @from_nid or @to_nid behaves as a wildcard.
*/
struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
hda_nid_t from_nid, hda_nid_t to_nid)
@@ -269,8 +291,14 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
-/* get the index number corresponding to the path instance;
- * the index starts from 1, for easier checking the invalid value
+/**
+ * snd_hda_get_path_idx - get the index number corresponding to the path
+ * instance
+ * @codec: the HDA codec
+ * @path: nid_path object
+ *
+ * The returned index starts from 1, i.e. the actual array index with offset 1,
+ * and zero is handled as an invalid path
*/
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
{
@@ -287,7 +315,12 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
}
EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
-/* get the path instance corresponding to the given index number */
+/**
+ * snd_hda_get_path_from_idx - get the path instance corresponding to the
+ * given index number
+ * @codec: the HDA codec
+ * @idx: the path index
+ */
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
{
struct hda_gen_spec *spec = codec->spec;
@@ -415,7 +448,18 @@ static bool __parse_nid_path(struct hda_codec *codec,
return true;
}
-/* parse the widget path from the given nid to the target nid;
+/**
+ * snd_hda_parse_nid_path - parse the widget path from the given nid to
+ * the target nid
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication
+ * @path: the path object to store the result
+ *
+ * Returns true if a matching path is found.
+ *
+ * The parsing behavior depends on parameters:
* when @from_nid is 0, try to find an empty DAC;
* when @anchor_nid is set to a positive value, only paths through the widget
* with the given value are evaluated.
@@ -436,9 +480,15 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
}
EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
-/*
- * parse the path between the given NIDs and add to the path list.
- * if no valid path is found, return NULL
+/**
+ * snd_hda_add_new_path - parse the path between the given NIDs and
+ * add to the path list
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
+ *
+ * If no valid path is found, returns NULL.
*/
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
@@ -724,8 +774,14 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
}
}
-/* activate or deactivate the given path
- * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
+/**
+ * snd_hda_activate_path - activate or deactivate the given path
+ * @codec: the HDA codec
+ * @path: the path to activate/deactivate
+ * @enable: flag to activate or not
+ * @add_aamix: enable the input from aamix NID
+ *
+ * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
*/
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
bool enable, bool add_aamix)
@@ -1038,11 +1094,24 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
break;
*index = ch;
return "Headphone";
+ case AUTO_PIN_LINE_OUT:
+ /* This deals with the case where we have two DACs and
+ * one LO, one HP and one Speaker */
+ if (!ch && cfg->speaker_outs && cfg->hp_outs) {
+ bool hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
+ bool spk_lo_shared = !path_has_mixer(codec, spec->speaker_paths[0], ctl_type);
+ if (hp_lo_shared && spk_lo_shared)
+ return spec->vmaster_mute.hook ? "PCM" : "Master";
+ if (hp_lo_shared)
+ return "Headphone+LO";
+ if (spk_lo_shared)
+ return "Speaker+LO";
+ }
}
/* for a single channel output, we don't have to name the channel */
if (cfg->line_outs == 1 && !spec->multi_ios)
- return "PCM";
+ return "Line Out";
if (ch >= ARRAY_SIZE(channel_name)) {
snd_BUG();
@@ -3149,12 +3218,13 @@ static int create_input_ctls(struct hda_codec *codec)
}
/* add stereo mix when explicitly enabled via hint */
- if (mixer && spec->add_stereo_mix_input &&
- snd_hda_get_bool_hint(codec, "add_stereo_mix_input") > 0) {
+ if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) {
err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
"Stereo Mix", 0);
if (err < 0)
return err;
+ else
+ spec->suppress_auto_mic = 1;
}
return 0;
@@ -3870,7 +3940,12 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
}
}
-/* Toggle outputs muting */
+/**
+ * snd_hda_gen_update_outputs - Toggle outputs muting
+ * @codec: the HDA codec
+ *
+ * Update the mute status of all outputs based on the current jack states.
+ */
void snd_hda_gen_update_outputs(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -3931,7 +4006,11 @@ static void call_update_outputs(struct hda_codec *codec)
snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
}
-/* standard HP-automute helper */
+/**
+ * snd_hda_gen_hp_automute - standard HP-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -3952,7 +4031,11 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
-/* standard line-out-automute helper */
+/**
+ * snd_hda_gen_line_automute - standard line-out-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_line_automute(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -3973,7 +4056,11 @@ void snd_hda_gen_line_automute(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
-/* standard mic auto-switch helper */
+/**
+ * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -4305,7 +4392,13 @@ static int check_auto_mic_availability(struct hda_codec *codec)
return 0;
}
-/* power_filter hook; make inactive widgets into power down */
+/**
+ * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
+ * into power down
+ * @codec: the HDA codec
+ * @nid: NID to evalute
+ * @power_state: target power state
+ */
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
@@ -4341,8 +4434,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
}
}
-/*
- * Parse the given BIOS configuration and set up the hda_gen_spec
+/**
+ * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
+ * set up the hda_gen_spec
+ * @codec: the HDA codec
+ * @cfg: Parsed pin configuration
*
* return 1 if successful, 0 if the proper config is not found,
* or a negative error code
@@ -4447,9 +4543,8 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
/* add stereo mix if available and not enabled yet */
if (!spec->auto_mic && spec->mixer_nid &&
- spec->add_stereo_mix_input &&
- spec->input_mux.num_items > 1 &&
- snd_hda_get_bool_hint(codec, "add_stereo_mix_input") < 0) {
+ spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO &&
+ spec->input_mux.num_items > 1) {
err = parse_capture_source(codec, spec->mixer_nid,
CFG_IDX_MIX, spec->num_all_adcs,
"Stereo Mix", 0);
@@ -4524,10 +4619,16 @@ static const char * const slave_pfxs[] = {
"CLFE", "Bass Speaker", "PCM",
"Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
"Headphone Front", "Headphone Surround", "Headphone CLFE",
- "Headphone Side",
+ "Headphone Side", "Headphone+LO", "Speaker+LO",
NULL,
};
+/**
+ * snd_hda_gen_build_controls - Build controls from the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_controls patch_ops.
+ */
int snd_hda_gen_build_controls(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -5005,7 +5106,12 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
strlcat(str, sfx, len);
}
-/* build PCM streams based on the parsed results */
+/**
+ * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_pcms patch_ops.
+ */
int snd_hda_gen_build_pcms(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -5300,9 +5406,11 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
}
}
-/*
- * initialize the generic spec;
- * this can be put as patch_ops.init function
+/**
+ * snd_hda_gen_init - initialize the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops init function.
*/
int snd_hda_gen_init(struct hda_codec *codec)
{
@@ -5338,9 +5446,11 @@ int snd_hda_gen_init(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_init);
-/*
- * free the generic spec;
- * this can be put as patch_ops.free function
+/**
+ * snd_hda_gen_free - free the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops free function.
*/
void snd_hda_gen_free(struct hda_codec *codec)
{
@@ -5352,9 +5462,12 @@ void snd_hda_gen_free(struct hda_codec *codec)
EXPORT_SYMBOL_GPL(snd_hda_gen_free);
#ifdef CONFIG_PM
-/*
- * check the loopback power save state;
- * this can be put as patch_ops.check_power_status function
+/**
+ * snd_hda_gen_check_power_status - check the loopback power save state
+ * @codec: the HDA codec
+ * @nid: NID to inspect
+ *
+ * This can be put as patch_ops check_power_status function.
*/
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
@@ -5380,6 +5493,12 @@ static const struct hda_codec_ops generic_patch_ops = {
#endif
};
+/**
+ * snd_hda_parse_generic_codec - Generic codec parser
+ * @codec: the HDA codec
+ *
+ * This should be called from the HDA codec core.
+ */
int snd_hda_parse_generic_codec(struct hda_codec *codec)
{
struct hda_gen_spec *spec;
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 61dd5153f512..3d852660443a 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -222,7 +222,7 @@ struct hda_gen_spec {
unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */
unsigned int indep_hp:1; /* independent HP supported */
unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
- unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */
+ unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
unsigned int power_down_unused:1; /* power down unused widgets */
unsigned int dac_min_mute:1; /* minimal = mute for DACs */
@@ -291,6 +291,13 @@ struct hda_gen_spec {
struct hda_jack_callback *cb);
};
+/* values for add_stereo_mix_input flag */
+enum {
+ HDA_HINT_STEREO_MIX_DISABLE, /* No stereo mix input */
+ HDA_HINT_STEREO_MIX_ENABLE, /* Add stereo mix input */
+ HDA_HINT_STEREO_MIX_AUTO, /* Add only if auto-mic is disabled */
+};
+
int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
int snd_hda_gen_init(struct hda_codec *codec);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 48b6c5a3884f..5ac0d39d59bc 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -196,8 +196,8 @@ MODULE_PARM_DESC(align_buffer_size,
"Force buffer and period sizes to be multiple of 128 bytes.");
#ifdef CONFIG_X86
-static bool hda_snoop = true;
-module_param_named(snoop, hda_snoop, bool, 0444);
+static int hda_snoop = -1;
+module_param_named(snoop, hda_snoop, bint, 0444);
MODULE_PARM_DESC(snoop, "Enable/disable snooping");
#else
#define hda_snoop true
@@ -272,43 +272,56 @@ enum {
AZX_NUM_DRIVERS, /* keep this as last entry */
};
+#define azx_get_snoop_type(chip) \
+ (((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10)
+#define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10)
+
+/* quirks for old Intel chipsets */
+#define AZX_DCAPS_INTEL_ICH \
+ (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
+
/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_NOPM \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
- AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_REVERSE_ASSIGN)
+ (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
+ AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH))
#define AZX_DCAPS_INTEL_PCH \
(AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
#define AZX_DCAPS_INTEL_HASWELL \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \
- AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \
- AZX_DCAPS_I915_POWERWELL)
+ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
+ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
+ AZX_DCAPS_SNOOP_TYPE(SCH))
/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
#define AZX_DCAPS_INTEL_BROADWELL \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \
- AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_PM_RUNTIME | \
- AZX_DCAPS_I915_POWERWELL)
+ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
+ AZX_DCAPS_SNOOP_TYPE(SCH))
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
- (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
- AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_SNOOP_TYPE(ATI))
/* quirks for ATI/AMD HDMI */
#define AZX_DCAPS_PRESET_ATI_HDMI \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\
AZX_DCAPS_NO_MSI64)
+/* quirks for ATI HDMI with snoop off */
+#define AZX_DCAPS_PRESET_ATI_HDMI_NS \
+ (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
+
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
- (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
- AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\
- AZX_DCAPS_CORBRP_SELF_CLEAR)
+ (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
+ AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\
+ AZX_DCAPS_SNOOP_TYPE(NVIDIA))
#define AZX_DCAPS_PRESET_CTHDA \
- (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
+ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
/*
* VGA-switcher support
@@ -437,6 +450,8 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
static void azx_init_pci(struct azx *chip)
{
+ int snoop_type = azx_get_snoop_type(chip);
+
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
* Ensuring these bits are 0 clears playback static on some HD Audio
@@ -451,7 +466,7 @@ static void azx_init_pci(struct azx *chip)
/* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
* we need to enable snoop.
*/
- if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_ATI) {
dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
azx_snoop(chip));
update_pci_byte(chip->pci,
@@ -460,7 +475,7 @@ static void azx_init_pci(struct azx *chip)
}
/* For NVIDIA HDA, enable snoop */
- if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_NVIDIA) {
dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
azx_snoop(chip));
update_pci_byte(chip->pci,
@@ -475,7 +490,7 @@ static void azx_init_pci(struct azx *chip)
}
/* Enable SCH/PCH snoop if needed */
- if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_SCH) {
unsigned short snoop;
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
@@ -1132,8 +1147,7 @@ static int azx_free(struct azx *chip)
pci_disable_device(chip->pci);
kfree(chip->azx_dev);
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (chip->fw)
- release_firmware(chip->fw);
+ release_firmware(chip->fw);
#endif
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(false);
@@ -1361,35 +1375,33 @@ static void check_msi(struct azx *chip)
/* check the snoop mode availability */
static void azx_check_snoop_available(struct azx *chip)
{
- bool snoop = chip->snoop;
+ int snoop = hda_snoop;
- switch (chip->driver_type) {
- case AZX_DRIVER_VIA:
+ if (snoop >= 0) {
+ dev_info(chip->card->dev, "Force to %s mode by module option\n",
+ snoop ? "snoop" : "non-snoop");
+ chip->snoop = snoop;
+ return;
+ }
+
+ snoop = true;
+ if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE &&
+ chip->driver_type == AZX_DRIVER_VIA) {
/* force to non-snoop mode for a new VIA controller
* when BIOS is set
*/
- if (snoop) {
- u8 val;
- pci_read_config_byte(chip->pci, 0x42, &val);
- if (!(val & 0x80) && chip->pci->revision == 0x30)
- snoop = false;
- }
- break;
- case AZX_DRIVER_ATIHDMI_NS:
- /* new ATI HDMI requires non-snoop */
- snoop = false;
- break;
- case AZX_DRIVER_CTHDA:
- case AZX_DRIVER_CMEDIA:
- snoop = false;
- break;
+ u8 val;
+ pci_read_config_byte(chip->pci, 0x42, &val);
+ if (!(val & 0x80) && chip->pci->revision == 0x30)
+ snoop = false;
}
- if (snoop != chip->snoop) {
- dev_info(chip->card->dev, "Force to %s mode\n",
- snoop ? "snoop" : "non-snoop");
- chip->snoop = snoop;
- }
+ if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF)
+ snoop = false;
+
+ chip->snoop = snoop;
+ if (!snoop)
+ dev_info(chip->card->dev, "Force to non-snoop mode\n");
}
static void azx_probe_work(struct work_struct *work)
@@ -1449,7 +1461,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
check_probe_mask(chip, dev);
chip->single_cmd = single_cmd;
- chip->snoop = hda_snoop;
azx_check_snoop_available(chip);
if (bdl_pos_adj[dev] < 0) {
@@ -1557,10 +1568,8 @@ static int azx_first_init(struct azx *chip)
if (align_buffer_size >= 0)
chip->align_buffer_size = !!align_buffer_size;
else {
- if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
+ if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE)
chip->align_buffer_size = 0;
- else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE)
- chip->align_buffer_size = 1;
else
chip->align_buffer_size = 1;
}
@@ -2047,36 +2056,35 @@ static const struct pci_device_id azx_ids[] = {
/* Braswell */
{ PCI_DEVICE(0x8086, 0x2284),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
- /* ICH */
+ /* ICH6 */
{ PCI_DEVICE(0x8086, 0x2668),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH6 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH7 */
{ PCI_DEVICE(0x8086, 0x27d8),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH7 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ESB2 */
{ PCI_DEVICE(0x8086, 0x269a),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ESB2 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH8 */
{ PCI_DEVICE(0x8086, 0x284b),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH8 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH9 */
{ PCI_DEVICE(0x8086, 0x293e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH9 */
{ PCI_DEVICE(0x8086, 0x293f),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH10 */
{ PCI_DEVICE(0x8086, 0x3a3e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH10 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH10 */
{ PCI_DEVICE(0x8086, 0x3a6e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH10 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
/* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE },
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
/* ATI SB 450/600/700/800/900 */
{ PCI_DEVICE(0x1002, 0x437b),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
@@ -2131,13 +2139,13 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xaa98),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0x9902),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaaa0),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaaa8),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaab0),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
/* VIA VT8251/VT8237A */
{ PCI_DEVICE(0x1106, 0x3288),
.driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
@@ -2184,7 +2192,7 @@ static const struct pci_device_id azx_ids[] = {
/* CM8888 */
{ PCI_DEVICE(0x13f6, 0x5011),
.driver_data = AZX_DRIVER_CMEDIA |
- AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB },
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* VMware HDAudio */
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index f56765ae73a7..e664307617bd 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -20,6 +20,16 @@
#include "hda_auto_parser.h"
#include "hda_jack.h"
+/**
+ * is_jack_detectable - Check whether the given pin is jack-detectable
+ * @codec: the HDA codec
+ * @nid: pin NID
+ *
+ * Check whether the given pin is capable to report the jack detection.
+ * The jack detection might not work by various reasons, e.g. the jack
+ * detection is prohibited in the codec level, the pin config has
+ * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc.
+ */
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (codec->no_jack_detect)
@@ -57,6 +67,8 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
/**
* snd_hda_jack_tbl_get - query the jack-table entry for the given NID
+ * @codec: the HDA codec
+ * @nid: pin NID to refer to
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
@@ -75,6 +87,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get);
/**
* snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
+ * @codec: the HDA codec
+ * @tag: tag value to refer to
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
@@ -93,6 +107,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag);
/**
* snd_hda_jack_tbl_new - create a jack-table entry for the given NID
+ * @codec: the HDA codec
+ * @nid: pin NID to assign
*/
static struct hda_jack_tbl *
snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
@@ -162,6 +178,7 @@ static void jack_detect_update(struct hda_codec *codec,
/**
* snd_hda_set_dirty_all - Mark all the cached as dirty
+ * @codec: the HDA codec
*
* This function sets the dirty flag to all entries of jack table.
* It's called from the resume path in hda_codec.c.
@@ -218,6 +235,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
/**
* snd_hda_jack_detect_enable - enable the jack-detection
+ * @codec: the HDA codec
+ * @nid: pin NID to enable
+ * @func: callback function to register
*
* In the case of error, the return value will be a pointer embedded with
* errno. Check and handle the return value appropriately with standard
@@ -258,6 +278,14 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
+/**
+ * snd_hda_jack_detect_enable - Enable the jack detection on the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID to enable jack detection
+ *
+ * Enable the jack detection with the default callback. Returns zero if
+ * successful or a negative error code.
+ */
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid)
{
return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL));
@@ -266,6 +294,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
/**
* snd_hda_jack_set_gating_jack - Set gating jack.
+ * @codec: the HDA codec
+ * @gated_nid: gated pin NID
+ * @gating_nid: gating pin NID
*
* Indicates the gated jack is only valid when the gating jack is plugged.
*/
@@ -287,6 +318,7 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack);
/**
* snd_hda_jack_report_sync - sync the states of all jacks and report if changed
+ * @codec: the HDA codec
*/
void snd_hda_jack_report_sync(struct hda_codec *codec)
{
@@ -349,6 +381,11 @@ static void hda_free_jack_priv(struct snd_jack *jack)
/**
* snd_hda_jack_add_kctl - Add a kctl for the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID to assign
+ * @name: string name for the jack
+ * @idx: index number for the jack
+ * @phantom_jack: flag to deal as a phantom jack
*
* This assigns a jack-detection kctl to the given pin. The kcontrol
* will have the given name and index.
@@ -391,6 +428,15 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
+/**
+ * snd_hda_jack_add_kctl - Add a jack kctl for the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @name: the name string for the jack ctl
+ * @idx: the ctl index for the jack ctl
+ *
+ * This is a simple helper calling __snd_hda_jack_add_kctl().
+ */
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, int idx)
{
@@ -456,6 +502,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
+ * @codec: the HDA codec
+ * @cfg: pin config table to parse
*/
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
@@ -531,6 +579,11 @@ static void call_jack_callback(struct hda_codec *codec,
}
}
+/**
+ * snd_hda_jack_unsol_event - Handle an unsolicited event
+ * @codec: the HDA codec
+ * @res: the unsolicited event data
+ */
void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct hda_jack_tbl *event;
@@ -546,6 +599,13 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
}
EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
+/**
+ * snd_hda_jack_poll_all - Poll all jacks
+ * @codec: the HDA codec
+ *
+ * Poll all detectable jacks with dirty flag, update the status, call
+ * callbacks and call snd_hda_jack_report_sync() if any changes are found.
+ */
void snd_hda_jack_poll_all(struct hda_codec *codec)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 13cb375454f6..b279e327a23b 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -72,6 +72,11 @@ enum {
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
+/**
+ * snd_hda_jack_detect - Detect the jack
+ * @codec: the HDA codec
+ * @nid: pin NID to check jack detection
+ */
static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
index 5016014e57f2..aa484fdf4338 100644
--- a/sound/pci/hda/hda_priv.h
+++ b/sound/pci/hda/hda_priv.h
@@ -152,9 +152,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* bits 0-7 are used for indicating driver type */
#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */
#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */
-#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */
-#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */
-#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */
+#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */
+#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */
#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */
#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
@@ -163,8 +162,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
-#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
-#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
+#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */
+/* 22 unused */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
@@ -173,6 +172,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
+enum {
+ AZX_SNOOP_TYPE_NONE ,
+ AZX_SNOOP_TYPE_SCH,
+ AZX_SNOOP_TYPE_ATI,
+ AZX_SNOOP_TYPE_NVIDIA,
+};
+
/* HD Audio class code */
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index 9b49f156a12e..ccc962a1699f 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -417,8 +417,13 @@ static DEVICE_ATTR_RW(user_pin_configs);
static DEVICE_ATTR_WO(reconfig);
static DEVICE_ATTR_WO(clear);
-/*
- * Look for hint string
+/**
+ * snd_hda_get_hint - Look for hint string
+ * @codec: the HDA codec
+ * @key: the hint key string
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and returns the value string. If nothing found, returns NULL.
*/
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
{
@@ -427,6 +432,15 @@ const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
}
EXPORT_SYMBOL_GPL(snd_hda_get_hint);
+/**
+ * snd_hda_get_bool_hint - Get a boolean hint value
+ * @codec: the HDA codec
+ * @key: the hint key string
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and returns a boolean value parsed from the value. If no matching
+ * key is found, return a negative value.
+ */
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
const char *p;
@@ -453,6 +467,16 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
}
EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
+/**
+ * snd_hda_get_int_hint - Get an integer hint value
+ * @codec: the HDA codec
+ * @key: the hint key string
+ * @valp: pointer to store a value
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and stores the integer value to @valp. If no matching key is found,
+ * return a negative error code. Otherwise it returns zero.
+ */
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
const char *p;
@@ -690,8 +714,11 @@ static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
return 1;
}
-/*
- * load a "patch" firmware file and parse it
+/**
+ * snd_hda_load_patch - load a "patch" firmware file and parse it
+ * @bus: HD-audio bus
+ * @fw_size: the firmware byte size
+ * @fw_buf: the firmware data
*/
int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
{
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 06275f8807a8..eb54da757407 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -195,7 +195,8 @@ static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
codec->no_sticky_stream = 1;
spec->gen.indep_hp = indep_hp;
- spec->gen.add_stereo_mix_input = 1;
+ if (!spec->gen.add_stereo_mix_input)
+ spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
@@ -332,6 +333,7 @@ static const struct hda_fixup ad1986a_fixups[] = {
static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+ SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
@@ -351,6 +353,7 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = {
{ .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
+ { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
{}
};
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 4f7ffa8c4a0d..e0383eea9880 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -2417,7 +2417,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
* @reloc: Relocation address for loading single-segment overlays, or 0 for
* no relocation
* @sample_rate: sampling rate of the stream used for DSP download
- * @number_channels: channels of the stream used for DSP download
+ * @channels: channels of the stream used for DSP download
* @ovly: TRUE if overlay format is required
*
* Returns zero or a negative error code.
@@ -2556,10 +2556,7 @@ static void dspload_post_setup(struct hda_codec *codec)
}
/**
- * Download DSP from a DSP Image Fast Load structure. This structure is a
- * linear, non-constant sized element array of structures, each of which
- * contain the count of the data to be loaded, the data itself, and the
- * corresponding starting chip address of the starting data location.
+ * dspload_image - Download DSP from a DSP Image Fast Load structure.
*
* @codec: the HDA codec
* @fls: pointer to a fast load image
@@ -2570,6 +2567,10 @@ static void dspload_post_setup(struct hda_codec *codec)
* @router_chans: number of audio router channels to be allocated (0 means use
* internal defaults; max is 32)
*
+ * Download DSP from a DSP Image Fast Load structure. This structure is a
+ * linear, non-constant sized element array of structures, each of which
+ * contain the count of the data to be loaded, the data itself, and the
+ * corresponding starting chip address of the starting data location.
* Returns zero or a negative error code.
*/
static int dspload_image(struct hda_codec *codec,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index e9ebc7bd752c..fd3ed18670e9 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -855,14 +855,14 @@ static int patch_conexant_auto(struct hda_codec *codec)
case 0x14f15045:
codec->single_adc_amp = 1;
spec->gen.mixer_nid = 0x17;
- spec->gen.add_stereo_mix_input = 1;
+ spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
snd_hda_pick_fixup(codec, cxt5045_fixup_models,
cxt5045_fixups, cxt_fixups);
break;
case 0x14f15047:
codec->pin_amp_workaround = 1;
spec->gen.mixer_nid = 0x19;
- spec->gen.add_stereo_mix_input = 1;
+ spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
snd_hda_pick_fixup(codec, cxt5047_fixup_models,
cxt5047_fixups, cxt_fixups);
break;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 9dc9cf8c90e9..5f13d2d18079 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -47,7 +47,9 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define is_haswell(codec) ((codec)->vendor_id == 0x80862807)
#define is_broadwell(codec) ((codec)->vendor_id == 0x80862808)
-#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec))
+#define is_skylake(codec) ((codec)->vendor_id == 0x80862809)
+#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
+ || is_skylake(codec))
#define is_valleyview(codec) ((codec)->vendor_id == 0x80862882)
#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883)
@@ -3365,6 +3367,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862807, .name = "Haswell HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862809, .name = "Skylake HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862883, .name = "Braswell HDMI", .patch = patch_generic_hdmi },
@@ -3425,6 +3428,7 @@ MODULE_ALIAS("snd-hda-codec-id:80862805");
MODULE_ALIAS("snd-hda-codec-id:80862806");
MODULE_ALIAS("snd-hda-codec-id:80862807");
MODULE_ALIAS("snd-hda-codec-id:80862808");
+MODULE_ALIAS("snd-hda-codec-id:80862809");
MODULE_ALIAS("snd-hda-codec-id:80862880");
MODULE_ALIAS("snd-hda-codec-id:80862882");
MODULE_ALIAS("snd-hda-codec-id:80862883");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b118a5be18df..a722067c491c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -96,6 +96,8 @@ struct alc_spec {
hda_nid_t cap_mute_led_nid;
unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
+ unsigned int gpio_mute_led_mask;
+ unsigned int gpio_mic_led_mask;
hda_nid_t headset_mic_pin;
hda_nid_t headphone_mic_pin;
@@ -3310,41 +3312,45 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
}
}
-/* turn on/off mute LED per vmaster hook */
-static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
+/* update LED status via GPIO */
+static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+ bool enabled)
{
- struct hda_codec *codec = private_data;
struct alc_spec *spec = codec->spec;
unsigned int oldval = spec->gpio_led;
+ if (spec->mute_led_polarity)
+ enabled = !enabled;
+
if (enabled)
- spec->gpio_led &= ~0x08;
+ spec->gpio_led &= ~mask;
else
- spec->gpio_led |= 0x08;
+ spec->gpio_led |= mask;
if (spec->gpio_led != oldval)
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
}
-/* turn on/off mic-mute LED per capture hook */
-static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void alc_fixup_gpio_mute_hook(void *private_data, int enabled)
{
+ struct hda_codec *codec = private_data;
struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
- if (!ucontrol)
- return;
+ alc_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- spec->gpio_led &= ~0x10;
- else
- spec->gpio_led |= 0x10;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (ucontrol)
+ alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1]);
}
static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
@@ -3358,9 +3364,33 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+ spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
+ spec->gpio_mic_led_mask = 0x10;
+ snd_hda_add_verbs(codec, gpio_init);
+ }
+}
+
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 },
+ {}
+ };
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x02;
+ spec->gpio_mic_led_mask = 0x20;
snd_hda_add_verbs(codec, gpio_init);
}
}
@@ -3402,9 +3432,11 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = led_power_filter;
@@ -3423,9 +3455,11 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = led_power_filter;
@@ -4300,6 +4334,7 @@ enum {
ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
ALC282_FIXUP_ASPIRE_V5_PINS,
ALC280_FIXUP_HP_GPIO4,
+ ALC286_FIXUP_HP_GPIO_LED,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -4769,6 +4804,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc280_fixup_hp_gpio4,
},
+ [ALC286_FIXUP_HP_GPIO_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc286_fixup_hp_gpio_led,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4809,6 +4848,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -4887,6 +4927,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
@@ -5697,22 +5738,6 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
}
}
-/* turn on/off mute LED per vmaster hook */
-static void alc662_led_gpio1_mute_hook(void *private_data, int enabled)
-{
- struct hda_codec *codec = private_data;
- struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
-
- if (enabled)
- spec->gpio_led |= 0x01;
- else
- spec->gpio_led &= ~0x01;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
-}
-
/* avoid D3 for keeping GPIO up */
static unsigned int gpio_led_power_filter(struct hda_codec *codec,
hda_nid_t nid,
@@ -5735,8 +5760,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 1;
+ spec->gpio_mute_led_mask = 0x01;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = gpio_led_power_filter;
}
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 6c206b6c8d65..3de6d3d779c9 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -137,7 +137,7 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
spec->gen.indep_hp = 1;
spec->gen.keep_eapd_on = 1;
spec->gen.pcm_playback_hook = via_playback_pcm_hook;
- spec->gen.add_stereo_mix_input = 1;
+ spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
return spec;
}
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 3b3cf4ac9060..c9411dfff5a4 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -205,13 +205,7 @@ static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
static const char * const texts[3] =
{"Internal Aux", "Wavetable", "Rear Line-In"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
@@ -1106,20 +1100,10 @@ static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_in
};
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
- } else {
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- }
- return 0;
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE)
+ return snd_ctl_enum_info(uinfo, 2, 8, universe_texts);
+ else
+ return snd_ctl_enum_info(uinfo, 2, 5, texts);
}
static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1167,16 +1151,10 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
"CD",
"Coax"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
- strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
+ return snd_ctl_enum_info(uinfo, 1, 2, prodigy_texts);
else
- strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, aureon_texts);
}
static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1392,15 +1370,7 @@ static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_
{
static const char * const texts[2] = { "128x", "64x" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 817a1bc50a60..5cb587cf360e 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -580,13 +580,7 @@ static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct s
static const char * const texts[2] = {
"+4dBu", "-10dBV",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ice1712_ewx_io_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -903,13 +897,7 @@ static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, st
static const char * const texts[4] = {
"Internal", "Front Input", "Rear Input", "Wave Table"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= 4)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ice1712_6fire_select_input_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 59e37c581691..a40001c1d9e8 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -309,11 +309,7 @@ static int snd_ice1712_value_init(struct snd_ice1712 *ice)
return err;
/* ak4524 controls */
- err = snd_ice1712_akm4xxx_build_controls(ice);
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ice1712_akm4xxx_build_controls(ice);
}
static int snd_ice1712_ez8_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 206ed2cbcef9..b039b46152c6 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -620,10 +620,9 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- u32 period_size, buf_size, rate, tmp, chn;
+ u32 period_size, rate, tmp, chn;
period_size = snd_pcm_lib_period_bytes(substream) - 1;
- buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
tmp = 0x0064;
if (snd_pcm_format_width(runtime->format) == 16)
tmp &= ~0x04;
@@ -1295,10 +1294,7 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd
return err;
}
- err = snd_ice1712_build_pro_mixer(ice);
- if (err < 0)
- return err;
- return 0;
+ return snd_ice1712_build_pro_mixer(ice);
}
/*
@@ -1545,10 +1541,9 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
dev_warn(ice->card->dev,
"cannot initialize ac97 for consumer, skipped\n");
else {
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
- if (err < 0)
- return err;
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97,
+ ice));
}
}
@@ -1839,13 +1834,7 @@ static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
"96000", /* 12: 7 */
"IEC958 Input", /* 13: -- */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 14;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 14, texts);
}
static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
@@ -1930,13 +1919,7 @@ static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcon
"96000", /* 12: 7 */
/* "IEC958 Input", 13: -- */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 13;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 13, texts);
}
static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcontrol,
@@ -2057,15 +2040,8 @@ static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
"IEC958 In L", "IEC958 In R", /* 9-10 */
"Digital Mixer", /* 11 - optional */
};
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items =
- snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ int num_items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol,
@@ -2516,11 +2492,8 @@ static int snd_ice1712_build_controls(struct snd_ice1712 *ice)
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
if (err < 0)
return err;
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
}
static int snd_ice1712_free(struct snd_ice1712 *ice)
@@ -2905,8 +2878,7 @@ static int snd_ice1712_resume(struct device *dev)
outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT));
outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03));
- if (ice->ac97)
- snd_ac97_resume(ice->ac97);
+ snd_ac97_resume(ice->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 08cb08ac85e6..d73da157ea14 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2049,13 +2049,7 @@ static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol,
"IEC958 In L", "IEC958 In R", /* 3-4 */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static inline int analog_route_shift(int idx)
@@ -2503,11 +2497,8 @@ static int snd_vt1724_build_controls(struct snd_ice1712 *ice)
return err;
}
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice));
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice));
}
static int snd_vt1724_free(struct snd_ice1712 *ice)
@@ -2884,8 +2875,7 @@ static int snd_vt1724_resume(struct device *dev)
outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG));
outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK));
- if (ice->ac97)
- snd_ac97_resume(ice->ac97);
+ snd_ac97_resume(ice->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 7a6c0786c55c..a1536c1a7ed4 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -475,11 +475,8 @@ static int juli_add_controls(struct snd_ice1712 *ice)
return err;
/* only capture SPDIF over AK4114 */
- err = snd_ak4114_build(spec->ak4114, NULL,
+ return snd_ak4114_build(spec->ak4114, NULL,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
- if (err < 0)
- return err;
- return 0;
}
/*
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c
index 63aa39f06f02..7de25c4807fd 100644
--- a/sound/pci/ice1712/maya44.c
+++ b/sound/pci/ice1712/maya44.c
@@ -359,15 +359,7 @@ static int maya_rec_src_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[] = { "Line", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int maya_rec_src_get(struct snd_kcontrol *kcontrol,
@@ -411,15 +403,7 @@ static int maya_pb_route_info(struct snd_kcontrol *kcontrol,
"Input 1", "Input 2", "Input 3", "Input 4"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int maya_pb_route_shift(int idx)
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index 0011e04f36a2..e9ca89c9174b 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -723,17 +723,7 @@ static int phase28_oversampling_info(struct snd_kcontrol *k,
{
static const char * const texts[2] = { "128x", "64x" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items -
- 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 5555eb4b2400..5101f40f6fbd 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -417,13 +417,7 @@ static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_inf
"Optical", /* RXP1 */
"CD", /* RXP2 */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index f3b491aa3e22..3919aed39ca0 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -284,15 +284,7 @@ static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[2] = { "Line In", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -563,13 +555,7 @@ static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[2] = { "Toslink", "Coax" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -772,10 +758,8 @@ static int prodigy192_init(struct snd_ice1712 *ice)
"AK4114 initialized with status %d\n", err);
} else
dev_dbg(ice->card->dev, "AK4114 not found\n");
- if (err < 0)
- return err;
- return 0;
+ return err;
}
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 2261d1e49150..2697402b5195 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -537,7 +537,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char* texts[32] = {
+ static const char * const texts[32] = {
"NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
@@ -560,14 +560,7 @@ static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 32;
- if (uinfo->value.enumerated.item > 31)
- uinfo->value.enumerated.item = 31;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 32, texts);
}
static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 2c2df4b74e01..6f55e02e5c84 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -46,7 +46,7 @@ struct qtet_kcontrol_private {
unsigned int bit;
void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
unsigned int (*get_register)(struct snd_ice1712 *ice);
- unsigned char * const texts[2];
+ const char * const texts[2];
};
enum {
@@ -554,17 +554,7 @@ static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[3] =
{"Line In 1/2", "Mic", "Mic + Low-cut"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
@@ -706,17 +696,8 @@ static int qtet_enum_info(struct snd_kcontrol *kcontrol,
{
struct qtet_kcontrol_private private =
qtet_privates[kcontrol->private_value];
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(private.texts);
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- private.texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts),
+ private.texts);
}
static int qtet_sw_get(struct snd_kcontrol *kcontrol,
@@ -852,11 +833,8 @@ static int qtet_add_controls(struct snd_ice1712 *ice)
if (err < 0)
return err;
/* only capture SPDIF over AK4113 */
- err = snd_ak4113_build(spec->ak4113,
+ return snd_ak4113_build(spec->ak4113,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
- if (err < 0)
- return err;
- return 0;
}
static inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 1112ec1953be..1d81ae677573 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -494,11 +494,13 @@ static int ap192_ak4114_init(struct snd_ice1712 *ice)
ap192_ak4114_write,
ak4114_init_vals, ak4114_init_txcsb,
ice, &spec->ak4114);
+ if (err < 0)
+ return err;
/* AK4114 in Revo cannot detect external rate correctly.
* No reason to stop capture stream due to incorrect checks */
spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
- return 0; /* error ignored; it's no fatal error */
+ return 0;
}
static int revo_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c
index ffd894bb4507..1c5d5b22c7a0 100644
--- a/sound/pci/ice1712/se.c
+++ b/sound/pci/ice1712/se.c
@@ -452,14 +452,7 @@ static int se200pci_cont_enum_info(struct snd_kcontrol *kc,
c = se200pci_get_enum_count(n);
if (!c)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = c;
- if (uinfo->value.enumerated.item >= c)
- uinfo->value.enumerated.item = c - 1;
- strcpy(uinfo->value.enumerated.name,
- se200pci_cont[n].member[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, c, se200pci_cont[n].member);
}
static int se200pci_cont_volume_get(struct snd_kcontrol *kc,
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 9fe549b2efdf..59d21c9401d2 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -444,9 +444,9 @@ static char *stateName[] = {
"Invalid"
};
-static char *clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" };
+static const char * const clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" };
-static char *clockSourceName[] = {
+static const char * const clockSourceName[] = {
"ADAT at 44.1 kHz",
"ADAT at 48 kHz",
"S/PDIF at 44.1 kHz",
@@ -455,7 +455,7 @@ static char *clockSourceName[] = {
"local clock at 48 kHz"
};
-static char *channelName[] = {
+static const char * const channelName[] = {
"ADAT-1",
"ADAT-2",
"ADAT-3",
@@ -1844,14 +1844,9 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
static int snd_korg1212_control_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = (kcontrol->private_value >= 8) ? 2 : 1;
- uinfo->value.enumerated.items = kAudioChannels;
- if (uinfo->value.enumerated.item > kAudioChannels-1) {
- uinfo->value.enumerated.item = kAudioChannels-1;
- }
- strcpy(uinfo->value.enumerated.name, channelName[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo,
+ (kcontrol->private_value >= 8) ? 2 : 1,
+ kAudioChannels, channelName);
}
static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol,
@@ -1961,14 +1956,7 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol,
static int snd_korg1212_control_sync_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2) {
- uinfo->value.enumerated.item = 2;
- }
- strcpy(uinfo->value.enumerated.name, clockSourceTypeName[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, clockSourceTypeName);
}
static int snd_korg1212_control_sync_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index a75c8dc66dec..4cf4be5ef82a 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -719,7 +719,7 @@ static int lola_probe(struct pci_dev *pci,
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
- dev_err(card->dev, "Error creating card!\n");
+ dev_err(&pci->dev, "Error creating card!\n");
return err;
}
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index 782f4d8299ae..e7fe15dd5a90 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -108,8 +108,7 @@ int lola_init_pins(struct lola *chip, int dir, int *nidp)
void lola_free_mixer(struct lola *chip)
{
- if (chip->mixer.array_saved)
- vfree(chip->mixer.array_saved);
+ vfree(chip->mixer.array_saved);
}
int lola_init_mixer_widget(struct lola *chip, int nid)
diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h
index 49d36bdd512c..469bcc685edf 100644
--- a/sound/pci/lx6464es/lx_defs.h
+++ b/sound/pci/lx6464es/lx_defs.h
@@ -175,7 +175,7 @@ enum buffer_flags {
BF_ZERO = 0x00, /* no flags (init).*/
};
-/**
+/*
* Stream Flags definitions
*/
enum stream_flags {
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 581e1e74863c..9996a4dead0f 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -37,10 +37,11 @@
/**
* wait for a value on a peudo register, exit with a timeout
*
- * @param mgr pointer to miXart manager structure
- * @param offset unsigned pseudo_register base + offset of value
- * @param value value
- * @param timeout timeout in centisenconds
+ * @mgr: pointer to miXart manager structure
+ * @offset: unsigned pseudo_register base + offset of value
+ * @is_egal: wait for the equal value
+ * @value: value
+ * @timeout: timeout in centisenconds
*/
static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
u32 offset, int is_egal,
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index b854fc5e01f5..c6092e48ceb6 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -501,10 +501,10 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
/*
* start or stop playback/capture substream
*/
-static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
+static int pcxhr_set_stream_state(struct snd_pcxhr *chip,
+ struct pcxhr_stream *stream)
{
int err;
- struct snd_pcxhr *chip;
struct pcxhr_rmh rmh;
int stream_mask, start;
@@ -512,8 +512,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
start = 1;
else {
if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) {
- snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state "
- "CANNOT be stopped\n");
+ dev_err(chip->card->dev,
+ "pcxhr_set_stream_state CANNOT be stopped\n");
return -EINVAL;
}
start = 0;
@@ -560,6 +560,7 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
struct pcxhr_rmh rmh;
unsigned int header;
+ chip = snd_pcm_substream_chip(stream->substream);
switch (stream->format) {
case SNDRV_PCM_FORMAT_U8:
header = HEADER_FMT_BASE_LIN;
@@ -582,11 +583,10 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL;
break;
default:
- snd_printk(KERN_ERR
- "error pcxhr_set_format() : unknown format\n");
+ dev_err(chip->card->dev,
+ "error pcxhr_set_format() : unknown format\n");
return -EINVAL;
}
- chip = snd_pcm_substream_chip(stream->substream);
sample_rate = chip->mgr->sample_rate;
if (sample_rate <= 32000 && sample_rate !=0) {
@@ -643,11 +643,11 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE);
stream_num = is_capture ? 0 : subs->number;
- snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : "
- "addr(%p) bytes(%zx) subs(%d)\n",
- is_capture ? 'c' : 'p',
- chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
- subs->runtime->dma_bytes, subs->number);
+ dev_dbg(chip->card->dev,
+ "pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
+ is_capture ? 'c' : 'p',
+ chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
+ subs->runtime->dma_bytes, subs->number);
pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
@@ -687,7 +687,7 @@ static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream,
*sample_count = ((snd_pcm_uframes_t)rmh.stat[0]) << 24;
*sample_count += (snd_pcm_uframes_t)rmh.stat[1];
}
- snd_printdd("PIPE_SAMPLE_COUNT = %lx\n", *sample_count);
+ dev_dbg(chip->card->dev, "PIPE_SAMPLE_COUNT = %lx\n", *sample_count);
return err;
}
#endif
@@ -711,8 +711,9 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
int playback_mask = 0;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- struct timeval my_tv1, my_tv2;
- do_gettimeofday(&my_tv1);
+ ktime_t start_time, stop_time, diff_time;
+
+ start_time = ktime_get();
#endif
mutex_lock(&mgr->setup_mutex);
@@ -778,12 +779,12 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
for (j = 0; j < chip->nb_streams_capt; j++) {
stream = &chip->capture_stream[j];
if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))
- err = pcxhr_set_stream_state(stream);
+ err = pcxhr_set_stream_state(chip, stream);
}
for (j = 0; j < chip->nb_streams_play; j++) {
stream = &chip->playback_stream[j];
if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))
- err = pcxhr_set_stream_state(stream);
+ err = pcxhr_set_stream_state(chip, stream);
}
}
@@ -823,9 +824,10 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
mutex_unlock(&mgr->setup_mutex);
#ifdef CONFIG_SND_DEBUG_VERBOSE
- do_gettimeofday(&my_tv2);
+ stop_time = ktime_get();
+ diff_time = ktime_sub(stop_time, start_time);
dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n",
- (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
+ (long)(ktime_to_ns(diff_time)), err);
#endif
}
@@ -837,12 +839,12 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
{
struct pcxhr_stream *stream;
struct snd_pcm_substream *s;
+ struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+ dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_START\n");
if (snd_pcm_stream_linked(subs)) {
- struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
snd_pcm_group_for_each_entry(s, subs) {
if (snd_pcm_substream_chip(s) != chip)
continue;
@@ -854,7 +856,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
pcxhr_start_linked_stream(chip->mgr);
} else {
stream = subs->runtime->private_data;
- snd_printdd("Only one Substream %c %d\n",
+ dev_dbg(chip->card->dev, "Only one Substream %c %d\n",
stream->pipe->is_capture ? 'C' : 'P',
stream->pipe->first_audio);
if (pcxhr_set_format(stream))
@@ -863,17 +865,17 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
return -EINVAL;
stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN;
- if (pcxhr_set_stream_state(stream))
+ if (pcxhr_set_stream_state(chip, stream))
return -EINVAL;
stream->status = PCXHR_STREAM_STATUS_RUNNING;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+ dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_STOP\n");
snd_pcm_group_for_each_entry(s, subs) {
stream = s->runtime->private_data;
stream->status = PCXHR_STREAM_STATUS_SCHEDULE_STOP;
- if (pcxhr_set_stream_state(stream))
+ if (pcxhr_set_stream_state(chip, stream))
return -EINVAL;
snd_pcm_trigger_done(s, subs);
}
@@ -1636,7 +1638,7 @@ static int pcxhr_probe(struct pci_dev *pci,
0, &card);
if (err < 0) {
- dev_err(card->dev, "cannot allocate the card %d\n", i);
+ dev_err(&pci->dev, "cannot allocate the card %d\n", i);
pcxhr_free(mgr);
return err;
}
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index a584acb61c00..181f7729d409 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -910,8 +910,9 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
int audio_mask;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- struct timeval my_tv1, my_tv2;
- do_gettimeofday(&my_tv1);
+ ktime_t start_time, stop_time, diff_time;
+
+ start_time = ktime_get();
#endif
audio_mask = (playback_mask |
(capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
@@ -960,9 +961,10 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
return err;
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
- do_gettimeofday(&my_tv2);
+ stop_time = ktime_get();
+ diff_time = ktime_sub(stop_time, start_time);
dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
- (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
+ (long)(ktime_to_ns(diff_time)), err);
#endif
return 0;
}
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index 95c9571780d8..63136c4f3f3d 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -660,14 +660,7 @@ static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol,
if (chip->mgr->board_has_mic)
i = 5; /* Mic and MicroMix available */
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = i;
- if (uinfo->value.enumerated.item > (i-1))
- uinfo->value.enumerated.item = i-1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, i, texts);
}
static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol,
@@ -756,14 +749,7 @@ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol,
texts = textsPCXHR;
snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1));
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = clock_items;
- if (uinfo->value.enumerated.item >= clock_items)
- uinfo->value.enumerated.item = clock_items-1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, clock_items, texts);
}
static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 4afd3cab775b..6c60dcd2e5a1 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1608,30 +1608,24 @@ snd_rme32_info_inputtype_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
- static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" };
+ static const char * const texts[4] = {
+ "Optical", "Coaxial", "Internal", "XLR"
+ };
+ int num_items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (rme32->pci->device) {
case PCI_DEVICE_ID_RME_DIGI32:
case PCI_DEVICE_ID_RME_DIGI32_8:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
case PCI_DEVICE_ID_RME_DIGI32_PRO:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
default:
snd_BUG();
- break;
- }
- if (uinfo->value.enumerated.item >
- uinfo->value.enumerated.items - 1) {
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
+ return -EINVAL;
}
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int
snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol,
@@ -1695,20 +1689,12 @@ static int
snd_rme32_info_clockmode_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "AutoSync",
+ static const char * const texts[4] = { "AutoSync",
"Internal 32.0kHz",
"Internal 44.1kHz",
"Internal 48.0kHz" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 5a395c87c6fc..2f1a85185a16 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1884,39 +1884,38 @@ snd_rme96_put_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
static int
snd_rme96_info_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *_texts[5] = { "Optical", "Coaxial", "Internal", "XLR", "Analog" };
+ static const char * const _texts[5] = {
+ "Optical", "Coaxial", "Internal", "XLR", "Analog"
+ };
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- char *texts[5] = { _texts[0], _texts[1], _texts[2], _texts[3], _texts[4] };
+ const char *texts[5] = {
+ _texts[0], _texts[1], _texts[2], _texts[3], _texts[4]
+ };
+ int num_items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (rme96->pci->device) {
case PCI_DEVICE_ID_RME_DIGI96:
case PCI_DEVICE_ID_RME_DIGI96_8:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PRO:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST:
if (rme96->rev > 4) {
/* PST */
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
texts[3] = _texts[4]; /* Analog instead of XLR */
} else {
/* PAD */
- uinfo->value.enumerated.items = 5;
+ num_items = 5;
}
break;
default:
snd_BUG();
- break;
- }
- if (uinfo->value.enumerated.item > uinfo->value.enumerated.items - 1) {
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ return -EINVAL;
}
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int
snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2002,16 +2001,9 @@ snd_rme96_put_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int
snd_rme96_info_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "AutoSync", "Internal", "Word" };
+ static const char * const texts[3] = { "AutoSync", "Internal", "Word" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2) {
- uinfo->value.enumerated.item = 2;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int
snd_rme96_get_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2041,16 +2033,11 @@ snd_rme96_put_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int
snd_rme96_info_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "0 dB", "-6 dB", "-12 dB", "-18 dB" };
+ static const char * const texts[4] = {
+ "0 dB", "-6 dB", "-12 dB", "-18 dB"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme96_get_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2081,16 +2068,9 @@ snd_rme96_put_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int
snd_rme96_info_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "1+2", "3+4", "5+6", "7+8" };
+ static const char * const texts[4] = { "1+2", "3+4", "5+6", "7+8" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme96_get_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 7646ba1664eb..cf5a6c8b9a63 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1680,16 +1680,13 @@ static int hdsp_set_spdif_input(struct hdsp *hdsp, int in)
static int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"};
+ static const char * const texts[4] = {
+ "Optical", "Coaxial", "Internal", "AES"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3);
- if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2))
- uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2);
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 4 : 3,
+ texts);
}
static int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1786,16 +1783,14 @@ static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
static int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
+ static const char * const texts[] = {
+ "32000", "44100", "48000", "64000", "88200", "96000",
+ "None", "128000", "176400", "192000"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1872,14 +1867,13 @@ static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct
static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[] = {
+ "32000", "44100", "48000", "64000", "88200", "96000",
+ "None", "128000", "176400", "192000"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1940,15 +1934,9 @@ static int hdsp_system_clock_mode(struct hdsp *hdsp)
static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Master", "Slave" };
+ static const char * const texts[] = {"Master", "Slave" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2049,19 +2037,16 @@ static int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" };
+ static const char * const texts[] = {
+ "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz",
+ "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz",
+ "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz",
+ "Internal 192.0 KHz"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (hdsp->io_type == H9632)
- uinfo->value.enumerated.items = 10;
- else
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2165,15 +2150,9 @@ static int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
+ static const char * const texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2250,15 +2229,9 @@ static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
+ static const char * const texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2335,15 +2308,9 @@ static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"0 dB", "-6 dB", "-12 dB"};
+ static const char * const texts[] = {"0 dB", "-6 dB", "-12 dB"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2439,31 +2406,28 @@ static int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref)
static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" };
+ static const char * const texts[] = {
+ "Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
+ int num_items;
switch (hdsp->io_type) {
case Digiface:
case H9652:
- uinfo->value.enumerated.items = 6;
+ num_items = 6;
break;
case Multiface:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
case H9632:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
default:
return -EINVAL;
}
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2543,15 +2507,11 @@ static int hdsp_autosync_ref(struct hdsp *hdsp)
static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" };
+ static const char * const texts[] = {
+ "Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 7, texts);
}
static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2738,14 +2698,9 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"No Lock", "Lock", "Sync" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[] = {"No Lock", "Lock", "Sync" };
+
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int hdsp_wc_sync_check(struct hdsp *hdsp)
@@ -3101,15 +3056,11 @@ static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
+ static const char * const texts[] = {
+ "Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
@@ -3234,15 +3185,9 @@ static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"On", "Off"};
+ static const char * const texts[] = {"On", "Off"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -3291,15 +3236,9 @@ static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd
static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"On", "Off"};
+ static const char * const texts[] = {"On", "Off"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
@@ -5368,8 +5307,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
snd_hdsp_free_buffers(hdsp);
- if (hdsp->firmware)
- release_firmware(hdsp->firmware);
+ release_firmware(hdsp->firmware);
vfree(hdsp->fw_uploaded);
if (hdsp->iobase)
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 52d86af3ef2d..3342705a5715 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1257,14 +1257,13 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
/* check for external sample rate, returns the sample rate in Hz*/
static int hdspm_external_sample_rate(struct hdspm *hdspm)
{
- unsigned int status, status2, timecode;
+ unsigned int status, status2;
int syncref, rate = 0, rate_bits;
switch (hdspm->io_type) {
case AES32:
status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
status = hdspm_read(hdspm, HDSPM_statusRegister);
- timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
syncref = hdspm_autosync_ref(hdspm);
switch (syncref) {
@@ -2202,10 +2201,10 @@ static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
return rate;
}
-/**
+/*
* Calculate the real sample rate from the
* current DDS value.
- **/
+ */
static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
{
unsigned int rate;
@@ -2271,9 +2270,9 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the WordClock sample rate class for the given card.
- **/
+ */
static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2296,9 +2295,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
}
-/**
+/*
* Returns the TCO sample rate class for the given card.
- **/
+ */
static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2322,9 +2321,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
}
-/**
+/*
* Returns the SYNC_IN sample rate class for the given card.
- **/
+ */
static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2344,9 +2343,9 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
return 0;
}
-/**
+/*
* Returns the AES sample rate class for the given card.
- **/
+ */
static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
{
int timecode;
@@ -2362,10 +2361,10 @@ static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
return 0;
}
-/**
+/*
* Returns the sample rate class for input source <idx> for
* 'new style' cards like the AIO and RayDAT.
- **/
+ */
static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
{
int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
@@ -2513,10 +2512,10 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the system clock mode for the given card.
* @returns 0 - master, 1 - slave
- **/
+ */
static int hdspm_system_clock_mode(struct hdspm *hdspm)
{
switch (hdspm->io_type) {
@@ -2535,10 +2534,10 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
}
-/**
+/*
* Sets the system clock mode.
* @param mode 0 - master, 1 - slave
- **/
+ */
static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
{
hdspm_set_toggle_setting(hdspm,
@@ -2645,18 +2644,7 @@ static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 9;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- texts_freq[uinfo->value.enumerated.item+1]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1);
}
static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol,
@@ -2704,11 +2692,11 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the current preferred sync reference setting.
* The semantics of the return value are depending on the
* card, please see the comments for clarification.
- **/
+ */
static int hdspm_pref_sync_ref(struct hdspm * hdspm)
{
switch (hdspm->io_type) {
@@ -2807,11 +2795,11 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm)
}
-/**
+/*
* Set the preferred sync reference to <pref>. The semantics
* of <pref> are depending on the card type, see the comments
* for clarification.
- **/
+ */
static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
{
int p = 0;
@@ -4113,9 +4101,9 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
-/**
+/*
* TCO controls
- **/
+ */
static void hdspm_tco_write(struct hdspm *hdspm)
{
unsigned int tc[4] = { 0, 0, 0, 0};
@@ -4873,18 +4861,15 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
- unsigned int status, status2, control, freq;
+ unsigned int status, status2;
char *pref_sync_ref;
char *autosync_ref;
char *system_clock_mode;
- char *insel;
int x, x2;
status = hdspm_read(hdspm, HDSPM_statusRegister);
status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- control = hdspm->control_register;
- freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
hdspm->card_name, hdspm->card->number + 1,
@@ -4947,17 +4932,6 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
snd_iprintf(buffer, "Line out: %s\n",
(hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
- switch (hdspm->control_register & HDSPM_InputMask) {
- case HDSPM_InputOptical:
- insel = "Optical";
- break;
- case HDSPM_InputCoaxial:
- insel = "Coaxial";
- break;
- default:
- insel = "Unknown";
- }
-
snd_iprintf(buffer,
"ClearTrackMarker = %s, Transmit in %s Channel Mode, "
"Auto Input %s\n",
@@ -5202,15 +5176,13 @@ snd_hdspm_proc_read_raydat(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
- unsigned int status1, status2, status3, control, i;
+ unsigned int status1, status2, status3, i;
unsigned int lock, sync;
status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */
status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */
status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */
- control = hdspm->control_register;
-
snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1);
snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2);
snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3);
@@ -5431,7 +5403,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
HDSPM_midi2IRQPending | HDSPM_midi3IRQPending);
/* now = get_cycles(); */
- /**
+ /*
* LAT_2..LAT_0 period counter (win) counter (mac)
* 6 4096 ~256053425 ~514672358
* 5 2048 ~128024983 ~257373821
@@ -5440,7 +5412,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
* 2 256 ~16003039 ~32260176
* 1 128 ~7998738 ~16194507
* 0 64 ~3998231 ~8191558
- **/
+ */
/*
dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
now-hdspm->last_interrupt, status & 0xFFC0);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index fa9a2a8dce5a..6521521853b8 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -920,15 +920,9 @@ static int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal)
static int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {"ADAT1", "Internal"};
+ static const char * const texts[2] = {"ADAT1", "Internal"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -991,15 +985,9 @@ static int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in)
static int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"ADAT1", "Coaxial", "Internal"};
+ static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1140,15 +1128,11 @@ static int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode)
static int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"AutoSync", "Master", "Word Clock"};
+ static const char * const texts[3] = {
+ "AutoSync", "Master", "Word Clock"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1231,16 +1215,14 @@ static int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref)
static int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"};
+ static const char * const texts[4] = {
+ "IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"
+ };
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1,
+ rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3,
+ texts);
}
static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1392,15 +1374,11 @@ static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_
static int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"No Lock", "Lock", "No Lock Sync", "Lock Sync"};
+ static const char * const texts[4] = {
+ "No Lock", "Lock", "No Lock Sync", "Lock Sync"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 5b0d317cc9a6..313a7328bf9c 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -918,17 +918,11 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
static int snd_sonicvibes_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[7] = {
+ static const char * const texts[7] = {
"CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= 7)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 7, texts);
}
static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index da875dced2ef..57cd757acfe7 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3702,8 +3702,7 @@ static int snd_trident_free(struct snd_trident *trident)
free_irq(trident->irq, trident);
if (trident->tlb.buffer.area) {
outl(0, TRID_REG(trident, NX_TLBC));
- if (trident->tlb.memhdr)
- snd_util_memhdr_free(trident->tlb.memhdr);
+ snd_util_memhdr_free(trident->tlb.memhdr);
if (trident->tlb.silent_page.area)
snd_dma_free_pages(&trident->tlb.silent_page);
vfree(trident->tlb.shadow_entries);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index ecedf4dbfa2a..e088467fb736 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1610,16 +1610,10 @@ static int snd_via8233_capture_source_info(struct snd_kcontrol *kcontrol,
/* formerly they were "Line" and "Mic", but it looks like that they
* have nothing to do with the actual physical connections...
*/
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Input1", "Input2"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_via8233_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 2d1570273e99..52c1a8d5b88a 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -92,6 +92,7 @@ static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg)
/**
* snd_vx_inb - read a byte from the register
+ * @chip: VX core instance
* @offset: register enum
*/
static unsigned char vx2_inb(struct vx_core *chip, int offset)
@@ -101,6 +102,7 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset)
/**
* snd_vx_outb - write a byte on the register
+ * @chip: VX core instance
* @offset: the register offset
* @val: the value to write
*/
@@ -114,6 +116,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
/**
* snd_vx_inl - read a 32bit word from the register
+ * @chip: VX core instance
* @offset: register enum
*/
static unsigned int vx2_inl(struct vx_core *chip, int offset)
@@ -123,6 +126,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
/**
* snd_vx_outl - write a 32bit word on the register
+ * @chip: VX core instance
* @offset: the register enum
* @val: the value to write
*/
@@ -223,6 +227,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
/**
* vx_setup_pseudo_dma - set up the pseudo dma read/write mode.
+ * @chip: VX core instance
* @do_write: 0 = read, 1 = set up for DMA write
*/
static void vx2_setup_pseudo_dma(struct vx_core *chip, int do_write)
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 92ec11456e3a..b16f42deed67 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -174,6 +174,7 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
/**
* snd_vxpocket_assign_resources - initialize the hardware and card instance.
+ * @chip: VX core instance
* @port: i/o port for the card
* @irq: irq number for the card
*
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 8a431bcb056c..5a13b22748b2 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -887,8 +887,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
}
}
- if (chip->pdev)
- pci_dev_put(chip->pdev);
+ pci_dev_put(chip->pdev);
of_node_put(chip->node);
kfree(chip);
return 0;
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index b9ffc17a4799..24c8766a925d 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -795,16 +795,11 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
static int snapper_info_capture_source(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Line", "Mic"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index b79a2a864513..33fb3bb133df 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -80,9 +80,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
/* stop RX and capture: will be enabled again at restart */
ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable);
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stop_xrun(substream);
/* now drain RHR and read status to remove xrun condition */
ssc_readx(prtd->ssc->regs, SSC_RHR);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index a609aafc994d..b2b108805b24 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -151,14 +151,7 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
*/
static void fsl_dma_abort_stream(struct snd_pcm_substream *substream)
{
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(substream, flags);
-
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-
- snd_pcm_stream_unlock_irqrestore(substream, flags);
+ snd_pcm_stop_xrun(substream);
}
/**
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 4e91bcaa3664..06606f9bbf78 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1285,19 +1285,11 @@ static int snd_cs4231_timer(struct snd_card *card)
static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Line", "CD", "Mic", "Mix"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 4, texts);
}
static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index 184e3987ac24..54656eed6e2e 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -25,8 +25,8 @@
#include "comm.h"
#include "chip.h"
-static char *opt_coax_texts[2] = { "Optical", "Coax" };
-static char *line_phono_texts[2] = { "Line", "Phono" };
+static const char * const opt_coax_texts[2] = { "Optical", "Coax" };
+static const char * const line_phono_texts[2] = { "Line", "Phono" };
/*
* data that needs to be sent to device. sets up card internal stuff.
@@ -327,14 +327,7 @@ static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- line_phono_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts);
}
static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
@@ -361,14 +354,7 @@ static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- opt_coax_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts);
}
static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 3b02e54b8f6d..62c25e74f0e5 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -316,7 +316,7 @@ static int usb6fire_fw_fpga_upload(
while (c != end) {
for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
- buffer[i] = byte_rev_table[(u8) *c];
+ buffer[i] = bitrev8((u8)*c);
ret = usb6fire_fw_fpga_write(device, buffer, i);
if (ret < 0) {
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index ba40489b2de4..36f4115eb1cd 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -679,25 +679,16 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
void usb6fire_pcm_abort(struct sfire_chip *chip)
{
struct pcm_runtime *rt = chip->pcm;
- unsigned long flags;
int i;
if (rt) {
rt->panic = true;
- if (rt->playback.instance) {
- snd_pcm_stream_lock_irqsave(rt->playback.instance, flags);
- snd_pcm_stop(rt->playback.instance,
- SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags);
- }
+ if (rt->playback.instance)
+ snd_pcm_stop_xrun(rt->playback.instance);
- if (rt->capture.instance) {
- snd_pcm_stream_lock_irqsave(rt->capture.instance, flags);
- snd_pcm_stop(rt->capture.instance,
- SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags);
- }
+ if (rt->capture.instance)
+ snd_pcm_stop_xrun(rt->capture.instance);
for (i = 0; i < PCM_N_URBS; i++) {
usb_poison_urb(&rt->in_urbs[i].instance);
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2b92f0dcbc4c..bcee4060fd18 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -9,6 +9,7 @@ snd-usb-audio-objs := card.o \
helper.o \
mixer.o \
mixer_quirks.o \
+ mixer_scarlett.o \
pcm.o \
proc.o \
quirks.o \
diff --git a/sound/usb/card.c b/sound/usb/card.c
index f61ebb17cc64..1fab9778807a 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -112,15 +112,13 @@ static struct usb_driver usb_audio_driver;
/*
* disconnect streams
- * called from snd_usb_audio_disconnect()
+ * called from usb_audio_disconnect()
*/
-static void snd_usb_stream_disconnect(struct list_head *head)
+static void snd_usb_stream_disconnect(struct snd_usb_stream *as)
{
int idx;
- struct snd_usb_stream *as;
struct snd_usb_substream *subs;
- as = list_entry(head, struct snd_usb_stream, list);
for (idx = 0; idx < 2; idx++) {
subs = &as->substream[idx];
if (!subs->num_formats)
@@ -307,10 +305,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
static int snd_usb_audio_free(struct snd_usb_audio *chip)
{
- struct list_head *p, *n;
+ struct snd_usb_endpoint *ep, *n;
- list_for_each_safe(p, n, &chip->ep_list)
- snd_usb_endpoint_free(p);
+ list_for_each_entry_safe(ep, n, &chip->ep_list, list)
+ snd_usb_endpoint_free(ep);
mutex_destroy(&chip->mutex);
kfree(chip);
@@ -323,16 +321,6 @@ static int snd_usb_audio_dev_free(struct snd_device *device)
return snd_usb_audio_free(chip);
}
-static void remove_trailing_spaces(char *str)
-{
- char *p;
-
- if (!*str)
- return;
- for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--)
- *p = 0;
-}
-
/*
* create a chip instance and set its names.
*/
@@ -416,7 +404,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
USB_ID_PRODUCT(chip->usb_id));
}
}
- remove_trailing_spaces(card->shortname);
+ strim(card->shortname);
/* retrieve the vendor and device strings as longname */
if (quirk && quirk->vendor_name && *quirk->vendor_name) {
@@ -430,7 +418,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
/* we don't really care if there isn't any vendor string */
}
if (len > 0) {
- remove_trailing_spaces(card->longname);
+ strim(card->longname);
if (*card->longname)
strlcat(card->longname, " ", sizeof(card->longname));
}
@@ -475,14 +463,14 @@ static int snd_usb_audio_create(struct usb_interface *intf,
* only at the first time. the successive calls of this function will
* append the pcm interface to the corresponding card.
*/
-static struct snd_usb_audio *
-snd_usb_audio_probe(struct usb_device *dev,
- struct usb_interface *intf,
- const struct usb_device_id *usb_id)
+static int usb_audio_probe(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
{
- const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info;
- int i, err;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ const struct snd_usb_audio_quirk *quirk =
+ (const struct snd_usb_audio_quirk *)usb_id->driver_info;
struct snd_usb_audio *chip;
+ int i, err;
struct usb_host_interface *alts;
int ifnum;
u32 id;
@@ -492,10 +480,11 @@ snd_usb_audio_probe(struct usb_device *dev,
id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
- goto __err_val;
+ return -ENXIO;
- if (snd_usb_apply_boot_quirk(dev, intf, quirk) < 0)
- goto __err_val;
+ err = snd_usb_apply_boot_quirk(dev, intf, quirk);
+ if (err < 0)
+ return err;
/*
* found a config. now register to ALSA
@@ -508,6 +497,7 @@ snd_usb_audio_probe(struct usb_device *dev,
if (usb_chip[i] && usb_chip[i]->dev == dev) {
if (usb_chip[i]->shutdown) {
dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
+ err = -EIO;
goto __error;
}
chip = usb_chip[i];
@@ -523,15 +513,16 @@ snd_usb_audio_probe(struct usb_device *dev,
if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
(pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
- if (snd_usb_audio_create(intf, dev, i, quirk,
- &chip) < 0) {
+ err = snd_usb_audio_create(intf, dev, i, quirk,
+ &chip);
+ if (err < 0)
goto __error;
- }
chip->pm_intf = intf;
break;
}
if (!chip) {
dev_err(&dev->dev, "no available usb audio device\n");
+ err = -ENODEV;
goto __error;
}
}
@@ -548,28 +539,32 @@ snd_usb_audio_probe(struct usb_device *dev,
err = 1; /* continue */
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
/* need some special handlings */
- if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
+ err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk);
+ if (err < 0)
goto __error;
}
if (err > 0) {
/* create normal USB audio interfaces */
- if (snd_usb_create_streams(chip, ifnum) < 0 ||
- snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
+ err = snd_usb_create_streams(chip, ifnum);
+ if (err < 0)
+ goto __error;
+ err = snd_usb_create_mixer(chip, ifnum, ignore_ctl_error);
+ if (err < 0)
goto __error;
- }
}
/* we are allowed to call snd_card_register() many times */
- if (snd_card_register(chip->card) < 0) {
+ err = snd_card_register(chip->card);
+ if (err < 0)
goto __error;
- }
usb_chip[chip->index] = chip;
chip->num_interfaces++;
chip->probing = 0;
+ usb_set_intfdata(intf, chip);
mutex_unlock(&register_mutex);
- return chip;
+ return 0;
__error:
if (chip) {
@@ -578,17 +573,16 @@ snd_usb_audio_probe(struct usb_device *dev,
chip->probing = 0;
}
mutex_unlock(&register_mutex);
- __err_val:
- return NULL;
+ return err;
}
/*
* we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe().
*/
-static void snd_usb_audio_disconnect(struct usb_device *dev,
- struct snd_usb_audio *chip)
+static void usb_audio_disconnect(struct usb_interface *intf)
{
+ struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_card *card;
struct list_head *p;
bool was_shutdown;
@@ -604,12 +598,14 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
mutex_lock(&register_mutex);
if (!was_shutdown) {
+ struct snd_usb_stream *as;
struct snd_usb_endpoint *ep;
+ struct usb_mixer_interface *mixer;
snd_card_disconnect(card);
/* release the pcm resources */
- list_for_each(p, &chip->pcm_list) {
- snd_usb_stream_disconnect(p);
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ snd_usb_stream_disconnect(as);
}
/* release the endpoint resources */
list_for_each_entry(ep, &chip->ep_list, list) {
@@ -620,8 +616,8 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
snd_usbmidi_disconnect(p);
}
/* release mixer resources */
- list_for_each(p, &chip->mixer_list) {
- snd_usb_mixer_disconnect(p);
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ snd_usb_mixer_disconnect(mixer);
}
}
@@ -635,27 +631,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
}
}
-/*
- * new 2.5 USB kernel API
- */
-static int usb_audio_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct snd_usb_audio *chip;
- chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
- if (chip) {
- usb_set_intfdata(intf, chip);
- return 0;
- } else
- return -EIO;
-}
-
-static void usb_audio_disconnect(struct usb_interface *intf)
-{
- snd_usb_audio_disconnect(interface_to_usbdev(intf),
- usb_get_intfdata(intf));
-}
-
#ifdef CONFIG_PM
int snd_usb_autoresume(struct snd_usb_audio *chip)
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 114e3e7ff511..03b074419964 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -348,6 +348,8 @@ static void snd_complete_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_endpoint *ep = ctx->ep;
+ struct snd_pcm_substream *substream;
+ unsigned long flags;
int err;
if (unlikely(urb->status == -ENOENT || /* unlinked */
@@ -364,8 +366,6 @@ static void snd_complete_urb(struct urb *urb)
goto exit_clear;
if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
- unsigned long flags;
-
spin_lock_irqsave(&ep->lock, flags);
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
spin_unlock_irqrestore(&ep->lock, flags);
@@ -389,7 +389,10 @@ static void snd_complete_urb(struct urb *urb)
return;
usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);
- //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ if (ep->data_subs && ep->data_subs->pcm_substream) {
+ substream = ep->data_subs->pcm_substream;
+ snd_pcm_stop_xrun(substream);
+ }
exit_clear:
clear_bit(ctx->index, &ep->active_mask);
@@ -1002,15 +1005,12 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
/**
* snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
*
- * @ep: the list header of the endpoint to free
+ * @ep: the endpoint to free
*
* This free all resources of the given ep.
*/
-void snd_usb_endpoint_free(struct list_head *head)
+void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
{
- struct snd_usb_endpoint *ep;
-
- ep = list_entry(head, struct snd_usb_endpoint, list);
kfree(ep);
}
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index e61ee5c356a3..6428392d8f62 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -24,7 +24,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
-void snd_usb_endpoint_free(struct list_head *head);
+void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index d3d49525a16b..5bfb695547f8 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -365,6 +365,8 @@ static void snd_usbmidi_error_timer(unsigned long data)
if (in && in->error_resubmit) {
in->error_resubmit = 0;
for (j = 0; j < INPUT_URBS; ++j) {
+ if (atomic_read(&in->urbs[j]->use_count))
+ continue;
in->urbs[j]->dev = umidi->dev;
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
}
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index a1bab149df4d..9581089c28c5 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -613,24 +613,14 @@ static int start_usb_playback(struct ua101 *ua)
static void abort_alsa_capture(struct ua101 *ua)
{
- unsigned long flags;
-
- if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
- snd_pcm_stream_lock_irqsave(ua->capture.substream, flags);
- snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags);
- }
+ if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+ snd_pcm_stop_xrun(ua->capture.substream);
}
static void abort_alsa_playback(struct ua101 *ua)
{
- unsigned long flags;
-
- if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
- snd_pcm_stream_lock_irqsave(ua->playback.substream, flags);
- snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags);
- }
+ if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+ snd_pcm_stop_xrun(ua->playback.substream);
}
static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 6e354d326858..41650d5b93b7 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -136,6 +136,10 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
return strlcpy(buf, p->name, buflen);
}
+/* ignore the error value if ignore_ctl_error flag is set */
+#define filter_error(cval, err) \
+ ((cval)->head.mixer->ignore_ctl_error ? 0 : (err))
+
/* check whether the control should be ignored */
static inline int
check_ignored_ctl(const struct usbmix_name_map *p)
@@ -286,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
int validx, int *value_ret)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
int idx = 0, err;
- err = snd_usb_autoresume(cval->mixer->chip);
+ err = snd_usb_autoresume(chip);
if (err < 0)
return -EIO;
@@ -300,7 +304,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
while (timeout-- > 0) {
if (chip->shutdown)
break;
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, idx, buf, val_len) >= val_len) {
@@ -316,14 +320,14 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
out:
up_read(&chip->shutdown_rwsem);
- snd_usb_autosuspend(cval->mixer->chip);
+ snd_usb_autosuspend(chip);
return err;
}
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
int validx, int *value_ret)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */
unsigned char *val;
int idx = 0, ret, size;
@@ -347,7 +351,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
if (chip->shutdown) {
ret = -ENODEV;
} else {
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, idx, buf, size);
@@ -392,7 +396,7 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request,
{
validx += cval->idx_off;
- return (cval->mixer->protocol == UAC_VERSION_1) ?
+ return (cval->head.mixer->protocol == UAC_VERSION_1) ?
get_ctl_value_v1(cval, request, validx, value_ret) :
get_ctl_value_v2(cval, request, validx, value_ret);
}
@@ -412,7 +416,7 @@ static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
value);
}
-static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
+int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
int channel, int index, int *value)
{
int err;
@@ -423,8 +427,8 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
}
err = get_cur_mix_raw(cval, channel, value);
if (err < 0) {
- if (!cval->mixer->ignore_ctl_error)
- usb_audio_dbg(cval->mixer->chip,
+ if (!cval->head.mixer->ignore_ctl_error)
+ usb_audio_dbg(cval->head.mixer->chip,
"cannot get current value for control %d ch %d: err = %d\n",
cval->control, channel, err);
return err;
@@ -441,13 +445,13 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2];
int idx = 0, val_len, err, timeout = 10;
validx += cval->idx_off;
- if (cval->mixer->protocol == UAC_VERSION_1) {
+ if (cval->head.mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
} else { /* UAC_VERSION_2 */
/* audio class v2 controls are always 2 bytes in size */
@@ -472,7 +476,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
while (timeout-- > 0) {
if (chip->shutdown)
break;
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
if (snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
@@ -497,7 +501,7 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval,
return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
}
-static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int index, int value)
{
int err;
@@ -506,7 +510,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
cval->ch_readonly & (1 << (channel - 1));
if (read_only) {
- usb_audio_dbg(cval->mixer->chip,
+ usb_audio_dbg(cval->head.mixer->chip,
"%s(): channel %d of control %d is read_only\n",
__func__, channel, cval->control);
return 0;
@@ -565,10 +569,10 @@ static int check_matrix_bitmap(unsigned char *bmap,
* if failed, give up and free the control instance.
*/
-int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
struct snd_kcontrol *kctl)
{
- struct usb_mixer_elem_info *cval = kctl->private_data;
+ struct usb_mixer_interface *mixer = list->mixer;
int err;
while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
@@ -578,9 +582,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
err);
return err;
}
- cval->elem_id = &kctl->id;
- cval->next_id_elem = mixer->id_elems[cval->id];
- mixer->id_elems[cval->id] = cval;
+ list->kctl = kctl;
+ list->next_id_elem = mixer->id_elems[list->id];
+ mixer->id_elems[list->id] = list;
return 0;
}
@@ -815,7 +819,7 @@ static struct usb_feature_control_info audio_feature_info[] = {
};
/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl)
{
kfree(kctl->private_data);
kctl->private_data = NULL;
@@ -829,7 +833,7 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
switch (chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
@@ -954,10 +958,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
}
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
- usb_audio_err(cval->mixer->chip,
+ usb_audio_err(cval->head.mixer->chip,
"%d:%d: cannot get min/max values for control %d (id %d)\n",
- cval->id, snd_usb_ctrl_intf(cval->mixer->chip),
- cval->control, cval->id);
+ cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip),
+ cval->control, cval->head.id);
return -EINVAL;
}
if (get_ctl_value(cval, UAC_GET_RES,
@@ -998,7 +1002,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
else
test -= cval->res;
if (test < cval->min || test > cval->max ||
- set_cur_mix_value(cval, minchn, 0, test) ||
+ snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
get_cur_mix_raw(cval, minchn, &check)) {
cval->res = last_valid_res;
break;
@@ -1007,7 +1011,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
break;
cval->res *= 2;
}
- set_cur_mix_value(cval, minchn, 0, saved);
+ snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
}
cval->initialized = 1;
@@ -1061,7 +1065,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
kcontrol->vd[0].access &=
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
- snd_ctl_notify(cval->mixer->chip->card,
+ snd_ctl_notify(cval->head.mixer->chip->card,
SNDRV_CTL_EVENT_MASK_INFO,
&kcontrol->id);
}
@@ -1086,9 +1090,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
for (c = 0; c < MAX_CHANNELS; c++) {
if (!(cval->cmask & (1 << c)))
continue;
- err = get_cur_mix_value(cval, c + 1, cnt, &val);
+ err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = get_relative_value(cval, val);
ucontrol->value.integer.value[cnt] = val;
cnt++;
@@ -1096,9 +1100,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
return 0;
} else {
/* master channel */
- err = get_cur_mix_value(cval, 0, 0, &val);
+ err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = get_relative_value(cval, val);
ucontrol->value.integer.value[0] = val;
}
@@ -1118,26 +1122,26 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
for (c = 0; c < MAX_CHANNELS; c++) {
if (!(cval->cmask & (1 << c)))
continue;
- err = get_cur_mix_value(cval, c + 1, cnt, &oval);
+ err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[cnt];
val = get_abs_value(cval, val);
if (oval != val) {
- set_cur_mix_value(cval, c + 1, cnt, val);
+ snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
changed = 1;
}
cnt++;
}
} else {
/* master channel */
- err = get_cur_mix_value(cval, 0, 0, &oval);
+ err = snd_usb_get_cur_mix_value(cval, 0, 0, &oval);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
val = get_abs_value(cval, val);
if (val != oval) {
- set_cur_mix_value(cval, 0, 0, val);
+ snd_usb_set_cur_mix_value(cval, 0, 0, val);
changed = 1;
}
}
@@ -1231,8 +1235,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = control;
cval->cmask = ctl_mask;
cval->val_type = audio_feature_info[control-1].type;
@@ -1250,7 +1253,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
/*
* If all channels in the mask are marked read-only, make the control
- * read-only. set_cur_mix_value() will check the mask again and won't
+ * read-only. snd_usb_set_cur_mix_value() will check the mask again and won't
* issue write commands to read-only channels.
*/
if (cval->channels == readonly_mask)
@@ -1263,7 +1266,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kfree(cval);
return;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
mapped_name = len != 0;
@@ -1290,9 +1293,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
- len = snprintf(kctl->id.name,
- sizeof(kctl->id.name),
- "Feature %d", unitid);
+ snprintf(kctl->id.name, sizeof(kctl->id.name),
+ "Feature %d", unitid);
}
if (!mapped_name)
@@ -1305,9 +1307,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
*/
if (!mapped_name && !(state->oterm.type >> 16)) {
if ((state->oterm.type & 0xff00) == 0x0100)
- len = append_ctl_name(kctl, " Capture");
+ append_ctl_name(kctl, " Capture");
else
- len = append_ctl_name(kctl, " Playback");
+ append_ctl_name(kctl, " Playback");
}
append_ctl_name(kctl, control == UAC_FU_MUTE ?
" Switch" : " Volume");
@@ -1344,14 +1346,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
range);
usb_audio_warn(state->chip,
"[%d] FU [%s] ch = %d, val = %d/%d/%d",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max, cval->res);
}
usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max, cval->res);
- snd_usb_mixer_add_control(state->mixer, kctl);
+ snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -1525,8 +1527,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
if (!cval)
return;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = in_ch + 1; /* based on 1 */
cval->val_type = USB_MIXER_S16;
for (i = 0; i < num_outs; i++) {
@@ -1547,7 +1548,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
kfree(cval);
return;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len)
@@ -1558,8 +1559,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
append_ctl_name(kctl, " Volume");
usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
- cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
- snd_usb_mixer_add_control(state->mixer, kctl);
+ cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max);
+ snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -1629,12 +1630,10 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
int err, val;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
- if (err < 0 && cval->mixer->ignore_ctl_error) {
+ if (err < 0) {
ucontrol->value.integer.value[0] = cval->min;
- return 0;
+ return filter_error(cval, err);
}
- if (err < 0)
- return err;
val = get_relative_value(cval, val);
ucontrol->value.integer.value[0] = val;
return 0;
@@ -1648,11 +1647,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
- if (err < 0) {
- if (cval->mixer->ignore_ctl_error)
- return 0;
- return err;
- }
+ if (err < 0)
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
val = get_abs_value(cval, val);
if (val != oval) {
@@ -1814,8 +1810,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return -ENOMEM;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = valinfo->control;
cval->val_type = valinfo->val_type;
cval->channels = 1;
@@ -1847,7 +1842,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
kfree(cval);
return -ENOMEM;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
/* nothing */ ;
@@ -1868,10 +1863,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
usb_audio_dbg(state->chip,
"[%d] PU [%s] ch = %d, val = %d/%d\n",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max);
- err = snd_usb_mixer_add_control(state->mixer, kctl);
+ err = snd_usb_mixer_add_control(&cval->head, kctl);
if (err < 0)
return err;
}
@@ -1924,11 +1919,8 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
err = get_cur_ctl_value(cval, cval->control << 8, &val);
if (err < 0) {
- if (cval->mixer->ignore_ctl_error) {
- ucontrol->value.enumerated.item[0] = 0;
- return 0;
- }
- return err;
+ ucontrol->value.enumerated.item[0] = 0;
+ return filter_error(cval, err);
}
val = get_relative_value(cval, val);
ucontrol->value.enumerated.item[0] = val;
@@ -1943,11 +1935,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
- if (err < 0) {
- if (cval->mixer->ignore_ctl_error)
- return 0;
- return err;
- }
+ if (err < 0)
+ return filter_error(cval, err);
val = ucontrol->value.enumerated.item[0];
val = get_abs_value(cval, val);
if (val != oval) {
@@ -2024,8 +2013,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return -ENOMEM;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->val_type = USB_MIXER_U8;
cval->channels = 1;
cval->min = 1;
@@ -2096,11 +2084,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
}
usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
- cval->id, kctl->id.name, desc->bNrInPins);
- if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
- return err;
-
- return 0;
+ cval->head.id, kctl->id.name, desc->bNrInPins);
+ return snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -2245,25 +2230,21 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
{
- struct usb_mixer_elem_info *info;
+ struct usb_mixer_elem_list *list;
- for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
+ for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem)
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- info->elem_id);
+ &list->kctl->id);
}
static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
- int unitid,
- struct usb_mixer_elem_info *cval)
+ struct usb_mixer_elem_list *list)
{
+ struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
"S8", "U8", "S16", "U16"};
- snd_iprintf(buffer, " Unit: %i\n", unitid);
- if (cval->elem_id)
- snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n",
- cval->elem_id->name, cval->elem_id->index);
snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, "
- "channels=%i, type=\"%s\"\n", cval->id,
+ "channels=%i, type=\"%s\"\n", cval->head.id,
cval->control, cval->cmask, cval->channels,
val_types[cval->val_type]);
snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
@@ -2275,7 +2256,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
{
struct snd_usb_audio *chip = entry->private_data;
struct usb_mixer_interface *mixer;
- struct usb_mixer_elem_info *cval;
+ struct usb_mixer_elem_list *list;
int unitid;
list_for_each_entry(mixer, &chip->mixer_list, list) {
@@ -2285,9 +2266,17 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
mixer->ignore_ctl_error);
snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
- for (cval = mixer->id_elems[unitid]; cval;
- cval = cval->next_id_elem)
- snd_usb_mixer_dump_cval(buffer, unitid, cval);
+ for (list = mixer->id_elems[unitid]; list;
+ list = list->next_id_elem) {
+ snd_iprintf(buffer, " Unit: %i\n", list->id);
+ if (list->kctl)
+ snd_iprintf(buffer,
+ " Control: name=\"%s\", index=%i\n",
+ list->kctl->id.name,
+ list->kctl->id.index);
+ if (list->dump)
+ list->dump(buffer, list);
+ }
}
}
}
@@ -2295,7 +2284,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
int attribute, int value, int index)
{
- struct usb_mixer_elem_info *info;
+ struct usb_mixer_elem_list *list;
__u8 unitid = (index >> 8) & 0xff;
__u8 control = (value >> 8) & 0xff;
__u8 channel = value & 0xff;
@@ -2307,7 +2296,13 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
return;
}
- for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) {
+ for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) {
+ struct usb_mixer_elem_info *info;
+
+ if (!list->kctl)
+ continue;
+
+ info = (struct usb_mixer_elem_info *)list;
if (info->control != control)
continue;
@@ -2320,7 +2315,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
info->cached = 0;
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- info->elem_id);
+ &info->head.kctl->id);
break;
case UAC2_CS_RANGE:
@@ -2485,11 +2480,8 @@ _error:
return err;
}
-void snd_usb_mixer_disconnect(struct list_head *p)
+void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer)
{
- struct usb_mixer_interface *mixer;
-
- mixer = list_entry(p, struct usb_mixer_interface, list);
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
}
@@ -2521,8 +2513,9 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
return 0;
}
-static int restore_mixer_value(struct usb_mixer_elem_info *cval)
+static int restore_mixer_value(struct usb_mixer_elem_list *list)
{
+ struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
int c, err, idx;
if (cval->cmask) {
@@ -2531,7 +2524,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
if (!(cval->cmask & (1 << c)))
continue;
if (cval->cached & (1 << c)) {
- err = set_cur_mix_value(cval, c + 1, idx,
+ err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
cval->cache_val[idx]);
if (err < 0)
return err;
@@ -2541,7 +2534,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
} else {
/* master */
if (cval->cached) {
- err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
+ err = snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val);
if (err < 0)
return err;
}
@@ -2552,19 +2545,19 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
{
- struct usb_mixer_elem_info *cval;
+ struct usb_mixer_elem_list *list;
int id, err;
- /* FIXME: any mixer quirks? */
-
if (reset_resume) {
/* restore cached mixer values */
for (id = 0; id < MAX_ID_ELEMS; id++) {
- for (cval = mixer->id_elems[id]; cval;
- cval = cval->next_id_elem) {
- err = restore_mixer_value(cval);
- if (err < 0)
- return err;
+ for (list = mixer->id_elems[id]; list;
+ list = list->next_id_elem) {
+ if (list->resume) {
+ err = list->resume(list);
+ if (err < 0)
+ return err;
+ }
}
}
}
@@ -2572,3 +2565,15 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
return snd_usb_mixer_activate(mixer);
}
#endif
+
+void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
+ struct usb_mixer_interface *mixer,
+ int unitid)
+{
+ list->mixer = mixer;
+ list->id = unitid;
+ list->dump = snd_usb_mixer_dump_cval;
+#ifdef CONFIG_PM
+ list->resume = restore_mixer_value;
+#endif
+}
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 73b1f649447b..d3268f0ee2b3 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -1,6 +1,8 @@
#ifndef __USBMIXER_H
#define __USBMIXER_H
+#include <sound/info.h>
+
struct usb_mixer_interface {
struct snd_usb_audio *chip;
struct usb_host_interface *hostif;
@@ -8,7 +10,7 @@ struct usb_mixer_interface {
unsigned int ignore_ctl_error;
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
- struct usb_mixer_elem_info **id_elems;
+ struct usb_mixer_elem_list **id_elems;
/* the usb audio specification version this interface complies to */
int protocol;
@@ -20,9 +22,6 @@ struct usb_mixer_interface {
struct urb *rc_urb;
struct usb_ctrlrequest *rc_setup_packet;
u8 rc_buffer[6];
-
- u8 audigy2nx_leds[3];
- u8 xonar_u1_status;
};
#define MAX_CHANNELS 16 /* max logical channels */
@@ -36,11 +35,21 @@ enum {
USB_MIXER_U16,
};
-struct usb_mixer_elem_info {
+typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
+ struct usb_mixer_elem_list *list);
+typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem);
+
+struct usb_mixer_elem_list {
struct usb_mixer_interface *mixer;
- struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
- struct snd_ctl_elem_id *elem_id;
+ struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
+ struct snd_kcontrol *kctl;
unsigned int id;
+ usb_mixer_elem_dump_func_t dump;
+ usb_mixer_elem_resume_func_t resume;
+};
+
+struct usb_mixer_elem_info {
+ struct usb_mixer_elem_list head;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
unsigned int idx_off; /* Control index offset */
@@ -53,20 +62,25 @@ struct usb_mixer_elem_info {
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
+ void *private_data;
};
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
int ignore_error);
-void snd_usb_mixer_disconnect(struct list_head *p);
+void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer);
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
-int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
struct snd_kcontrol *kctl);
+void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
+ struct usb_mixer_interface *mixer,
+ int unitid);
+
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv);
@@ -75,4 +89,12 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
#endif
+int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+ int index, int value);
+
+int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
+ int channel, int index, int *value);
+
+extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl);
+
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index d1d72ff50347..1994d41348f8 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -179,6 +179,11 @@ static struct usbmix_name_map audigy2nx_map[] = {
{ 0 } /* terminator */
};
+static struct usbmix_name_map mbox1_map[] = {
+ { 1, "Clock" },
+ { 0 } /* terminator */
+};
+
static struct usbmix_selector_map c400_selectors[] = {
{
.id = 0x80,
@@ -416,6 +421,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.map = aureon_51_2_map,
},
{
+ .id = USB_ID(0x0dba, 0x1000),
+ .map = mbox1_map,
+ },
+ {
.id = USB_ID(0x13e5, 0x0001),
.map = scratch_live_map,
.ignore_ctl_error = 1,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 8c9bf4b7aaf0..dc9df007d3e3 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -41,6 +41,7 @@
#include "usbaudio.h"
#include "mixer.h"
#include "mixer_quirks.h"
+#include "mixer_scarlett.h"
#include "helper.h"
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
@@ -52,13 +53,6 @@ struct std_mono_table {
snd_kcontrol_tlv_rw_t *tlv_callback;
};
-/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
-{
- kfree(kctl->private_data);
- kctl->private_data = NULL;
-}
-
/* This function allows for the creation of standard UAC controls.
* See the quirks for M-Audio FTUs or Ebox-44.
* If you don't want to set a TLV callback pass NULL.
@@ -75,7 +69,6 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
const char *name,
snd_kcontrol_tlv_rw_t *tlv_callback)
{
- int err;
struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl;
@@ -83,8 +76,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
if (!cval)
return -ENOMEM;
- cval->id = unitid;
- cval->mixer = mixer;
+ snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid);
cval->val_type = val_type;
cval->channels = 1;
cval->control = control;
@@ -108,7 +100,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
/* Set name */
snprintf(kctl->id.name, sizeof(kctl->id.name), name);
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
/* set TLV */
if (tlv_callback) {
@@ -118,11 +110,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
}
/* Add control to mixer */
- err = snd_usb_mixer_add_control(mixer, kctl);
- if (err < 0)
- return err;
-
- return 0;
+ return snd_usb_mixer_add_control(&cval->head, kctl);
}
static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
@@ -156,6 +144,32 @@ static int snd_create_std_mono_table(struct usb_mixer_interface *mixer,
return 0;
}
+static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer,
+ int id,
+ usb_mixer_elem_resume_func_t resume,
+ const struct snd_kcontrol_new *knew,
+ struct usb_mixer_elem_list **listp)
+{
+ struct usb_mixer_elem_list *list;
+ struct snd_kcontrol *kctl;
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+ if (listp)
+ *listp = list;
+ list->mixer = mixer;
+ list->id = id;
+ list->resume = resume;
+ kctl = snd_ctl_new1(knew, list);
+ if (!kctl) {
+ kfree(list);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+ return snd_usb_mixer_add_control(list, kctl);
+}
+
/*
* Sound Blaster remote control configuration
*
@@ -283,84 +297,90 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int index = kcontrol->private_value;
-
- ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index];
+ ucontrol->value.integer.value[0] = kcontrol->private_value >> 8;
return 0;
}
-static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer,
+ int value, int index)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int index = kcontrol->private_value;
- int value = ucontrol->value.integer.value[0];
- int err, changed;
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
- if (value > 1)
- return -EINVAL;
- changed = value != mixer->audigy2nx_leds[index];
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown) {
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
err = -ENODEV;
goto out;
}
- if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ if (chip->usb_id == USB_ID(0x041e, 0x3042))
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0);
/* USB X-Fi S51 Pro */
- if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ if (chip->usb_id == USB_ID(0x041e, 0x30df))
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0);
else
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
value, index + 2, NULL, 0);
out:
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
- mixer->audigy2nx_leds[index] = value;
- return changed;
+ up_read(&chip->shutdown_rwsem);
+ return err;
}
-static struct snd_kcontrol_new snd_audigy2nx_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "CMSS LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 0,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Power LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 1,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Dolby Digital LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 2,
- },
+static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_interface *mixer = list->mixer;
+ int index = kcontrol->private_value & 0xff;
+ int value = ucontrol->value.integer.value[0];
+ int old_value = kcontrol->private_value >> 8;
+ int err;
+
+ if (value > 1)
+ return -EINVAL;
+ if (value == old_value)
+ return 0;
+ kcontrol->private_value = (value << 8) | index;
+ err = snd_audigy2nx_led_update(mixer, value, index);
+ return err < 0 ? err : 1;
+}
+
+static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list)
+{
+ int priv_value = list->kctl->private_value;
+
+ return snd_audigy2nx_led_update(list->mixer, priv_value >> 8,
+ priv_value & 0xff);
+}
+
+/* name and private_value are set dynamically */
+static struct snd_kcontrol_new snd_audigy2nx_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_audigy2nx_led_info,
+ .get = snd_audigy2nx_led_get,
+ .put = snd_audigy2nx_led_put,
+};
+
+static const char * const snd_audigy2nx_led_names[] = {
+ "CMSS LED Switch",
+ "Power LED Switch",
+ "Dolby Digital LED Switch",
};
static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
{
int i, err;
- for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+ for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) {
+ struct snd_kcontrol_new knew;
+
/* USB X-Fi S51 doesn't have a CMSS LED */
if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
continue;
@@ -373,12 +393,16 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
break;
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
+
+ knew = snd_audigy2nx_control;
+ knew.name = snd_audigy2nx_led_names[i];
+ knew.private_value = (1 << 8) | i; /* LED on as default */
+ err = add_single_ctl_with_resume(mixer, 0,
+ snd_audigy2nx_led_resume,
+ &knew, NULL);
if (err < 0)
return err;
}
- mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */
return 0;
}
@@ -437,19 +461,9 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[2] = {"1/2",
- "3/4"
- };
+ static const char * const texts[2] = {"1/2", "3/4"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
@@ -459,100 +473,122 @@ static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer,
+ int value)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- unsigned int value = ucontrol->value.enumerated.item[0];
- int err, changed;
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
unsigned char buf[2];
- if (value > 1)
- return -EINVAL;
-
- buf[0] = 0x01;
- buf[1] = value ? 0x02 : 0x01;
-
- changed = value != kcontrol->private_value;
- down_read(&mixer->chip->shutdown_rwsem);
+ down_read(&chip->shutdown_rwsem);
if (mixer->chip->shutdown) {
err = -ENODEV;
goto out;
}
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR,
+
+ buf[0] = 0x01;
+ buf[1] = value ? 0x02 : 0x01;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
0x0400, 0x0e00, buf, 2);
out:
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_interface *mixer = list->mixer;
+ unsigned int value = ucontrol->value.enumerated.item[0];
+ int err;
+
+ if (value > 1)
+ return -EINVAL;
+
+ if (value == kcontrol->private_value)
+ return 0;
+
kcontrol->private_value = value;
- return changed;
+ err = snd_emu0204_ch_switch_update(mixer, value);
+ return err < 0 ? err : 1;
}
+static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_emu0204_ch_switch_update(list->mixer,
+ list->kctl->private_value);
+}
-static struct snd_kcontrol_new snd_emu0204_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Front Jack Channels",
- .info = snd_emu0204_ch_switch_info,
- .get = snd_emu0204_ch_switch_get,
- .put = snd_emu0204_ch_switch_put,
- .private_value = 0,
- },
+static struct snd_kcontrol_new snd_emu0204_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Jack Channels",
+ .info = snd_emu0204_ch_switch_info,
+ .get = snd_emu0204_ch_switch_get,
+ .put = snd_emu0204_ch_switch_put,
+ .private_value = 0,
};
static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer)
{
- int i, err;
-
- for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) {
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_emu0204_controls[i], mixer));
- if (err < 0)
- return err;
- }
-
- return 0;
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_emu0204_ch_switch_resume,
+ &snd_emu0204_control, NULL);
}
+
/* ASUS Xonar U1 / U3 controls */
static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
-
- ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
+ ucontrol->value.integer.value[0] = !!(kcontrol->private_value & 0x02);
return 0;
}
+static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer,
+ unsigned char status)
+{
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ 50, 0, &status, 1);
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
u8 old_status, new_status;
- int err, changed;
+ int err;
- old_status = mixer->xonar_u1_status;
+ old_status = kcontrol->private_value;
if (ucontrol->value.integer.value[0])
new_status = old_status | 0x02;
else
new_status = old_status & ~0x02;
- changed = new_status != old_status;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
- 50, 0, &new_status, 1);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
- mixer->xonar_u1_status = new_status;
- return changed;
+ if (new_status == old_status)
+ return 0;
+
+ kcontrol->private_value = new_status;
+ err = snd_xonar_u1_switch_update(list->mixer, new_status);
+ return err < 0 ? err : 1;
+}
+
+static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_xonar_u1_switch_update(list->mixer,
+ list->kctl->private_value);
}
static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
@@ -561,82 +597,213 @@ static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
.info = snd_ctl_boolean_mono_info,
.get = snd_xonar_u1_switch_get,
.put = snd_xonar_u1_switch_put,
+ .private_value = 0x05,
};
static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
{
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_xonar_u1_switch_resume,
+ &snd_xonar_u1_output_switch, NULL);
+}
+
+/* Digidesign Mbox 1 clock source switch (internal/spdif) */
+
+static int snd_mbox1_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kctl->private_value;
+ return 0;
+}
+
+static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val)
+{
+ struct snd_usb_audio *chip = mixer->chip;
int err;
+ unsigned char buff[3];
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto err;
+ }
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
+ /* Prepare for magic command to toggle clock source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
if (err < 0)
- return err;
- mixer->xonar_u1_status = 0x05;
- return 0;
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+
+ /* 2 possibilities: Internal -> send sample rate
+ * S/PDIF sync -> send zeroes
+ * NB: Sample rate locked to 48kHz on purpose to
+ * prevent user from resetting the sample rate
+ * while S/PDIF sync is enabled and confusing
+ * this configuration.
+ */
+ if (val == 0) {
+ buff[0] = 0x80;
+ buff[1] = 0xbb;
+ buff[2] = 0x00;
+ } else {
+ buff[0] = buff[1] = buff[2] = 0x00;
+ }
+
+ /* Send the magic command to toggle the clock source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x1,
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3);
+ if (err < 0)
+ goto err;
+
+err:
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ struct usb_mixer_interface *mixer = list->mixer;
+ int err;
+ bool cur_val, new_val;
+
+ cur_val = kctl->private_value;
+ new_val = ucontrol->value.enumerated.item[0];
+ if (cur_val == new_val)
+ return 0;
+
+ kctl->private_value = new_val;
+ err = snd_mbox1_switch_update(mixer, new_val);
+ return err < 0 ? err : 1;
+}
+
+static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *const texts[2] = {
+ "Internal",
+ "S/PDIF"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int snd_mbox1_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_mbox1_switch_update(list->mixer, list->kctl->private_value);
+}
+
+static struct snd_kcontrol_new snd_mbox1_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Source",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_mbox1_switch_info,
+ .get = snd_mbox1_switch_get,
+ .put = snd_mbox1_switch_put,
+ .private_value = 0
+};
+
+static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer)
+{
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_mbox1_switch_resume,
+ &snd_mbox1_switch, NULL);
}
/* Native Instruments device quirks */
#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
-static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_ni_control_init_val(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
struct usb_device *dev = mixer->chip->dev;
- u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
- u16 wIndex = kcontrol->private_value & 0xffff;
- u8 tmp;
- int ret;
-
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- ret = -ENODEV;
- else
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, wIndex,
- &tmp, sizeof(tmp));
- up_read(&mixer->chip->shutdown_rwsem);
+ unsigned int pval = kctl->private_value;
+ u8 value;
+ int err;
- if (ret < 0) {
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+ (pval >> 16) & 0xff,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, pval & 0xffff, &value, 1);
+ if (err < 0) {
dev_err(&dev->dev,
- "unable to issue vendor read request (ret = %d)", ret);
- return ret;
+ "unable to issue vendor read request (ret = %d)", err);
+ return err;
}
- ucontrol->value.integer.value[0] = tmp;
+ kctl->private_value |= (value << 24);
+ return 0;
+}
+static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = kcontrol->private_value >> 24;
return 0;
}
+static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list)
+{
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
+ int err;
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
+ err = -ENODEV;
+ else
+ err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+ (pval >> 16) & 0xff,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ pval >> 24, pval & 0xffff, NULL, 0, 1000);
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- struct usb_device *dev = mixer->chip->dev;
- u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
- u16 wIndex = kcontrol->private_value & 0xffff;
- u16 wValue = ucontrol->value.integer.value[0];
- int ret;
-
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- ret = -ENODEV;
- else
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- wValue, wIndex,
- NULL, 0, 1000);
- up_read(&mixer->chip->shutdown_rwsem);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ u8 oldval = (kcontrol->private_value >> 24) & 0xff;
+ u8 newval = ucontrol->value.integer.value[0];
+ int err;
- if (ret < 0) {
- dev_err(&dev->dev,
- "unable to issue vendor write request (ret = %d)", ret);
- return ret;
- }
+ if (oldval == newval)
+ return 0;
- return 0;
+ kcontrol->private_value &= ~(0xff << 24);
+ kcontrol->private_value |= newval;
+ err = snd_ni_update_cur_val(list);
+ return err < 0 ? err : 1;
}
static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
@@ -707,16 +874,17 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
};
for (i = 0; i < count; i++) {
- struct snd_kcontrol *c;
+ struct usb_mixer_elem_list *list;
template.name = kc[i].name;
template.private_value = kc[i].private_value;
- c = snd_ctl_new1(&template, mixer);
- err = snd_ctl_add(mixer->chip->card, c);
-
+ err = add_single_ctl_with_resume(mixer, 0,
+ snd_ni_update_cur_val,
+ &template, &list);
if (err < 0)
break;
+ snd_ni_control_init_val(mixer, list->kctl);
}
return err;
@@ -724,170 +892,88 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
/* M-Audio FastTrack Ultra quirks */
/* FTU Effect switch (also used by C400/C600) */
-struct snd_ftu_eff_switch_priv_val {
- struct usb_mixer_interface *mixer;
- int cached_value;
- int is_cached;
- int bUnitID;
- int validx;
-};
-
static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[8] = {"Room 1",
- "Room 2",
- "Room 3",
- "Hall 1",
- "Hall 2",
- "Plate",
- "Delay",
- "Echo"
+ static const char *const texts[8] = {
+ "Room 1", "Room 2", "Room 3", "Hall 1",
+ "Hall 2", "Plate", "Delay", "Echo"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
-static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
{
- struct snd_usb_audio *chip;
- struct usb_mixer_interface *mixer;
- struct snd_ftu_eff_switch_priv_val *pval;
+ struct usb_device *dev = mixer->chip->dev;
+ unsigned int pval = kctl->private_value;
int err;
unsigned char value[2];
- int id, validx;
-
- const int val_len = 2;
value[0] = 0x00;
value[1] = 0x00;
- pval = (struct snd_ftu_eff_switch_priv_val *)
- kctl->private_value;
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ pval & 0xff00,
+ snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
+ value, 2);
+ if (err < 0)
+ return err;
- if (pval->is_cached) {
- ucontrol->value.enumerated.item[0] = pval->cached_value;
- return 0;
- }
+ kctl->private_value |= value[0] << 24;
+ return 0;
+}
- mixer = (struct usb_mixer_interface *) pval->mixer;
- if (snd_BUG_ON(!mixer))
- return -EINVAL;
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kctl->private_value >> 24;
+ return 0;
+}
- chip = (struct snd_usb_audio *) mixer->chip;
- if (snd_BUG_ON(!chip))
- return -EINVAL;
+static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
+{
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
+ unsigned char value[2];
+ int err;
- id = pval->bUnitID;
- validx = pval->validx;
+ value[0] = pval >> 24;
+ value[1] = 0;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
err = -ENODEV;
else
err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- ucontrol->value.enumerated.item[0] = value[0];
- pval->cached_value = value[0];
- pval->is_cached = 1;
-
- return 0;
+ usb_sndctrlpipe(chip->dev, 0),
+ UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ pval & 0xff00,
+ snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
+ value, 2);
+ up_read(&chip->shutdown_rwsem);
+ return err;
}
static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_usb_audio *chip;
- struct snd_ftu_eff_switch_priv_val *pval;
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ unsigned int pval = list->kctl->private_value;
+ int cur_val, err, new_val;
- struct usb_mixer_interface *mixer;
- int changed, cur_val, err, new_val;
- unsigned char value[2];
- int id, validx;
-
- const int val_len = 2;
-
- changed = 0;
-
- pval = (struct snd_ftu_eff_switch_priv_val *)
- kctl->private_value;
- cur_val = pval->cached_value;
+ cur_val = pval >> 24;
new_val = ucontrol->value.enumerated.item[0];
+ if (cur_val == new_val)
+ return 0;
- mixer = (struct usb_mixer_interface *) pval->mixer;
- if (snd_BUG_ON(!mixer))
- return -EINVAL;
-
- chip = (struct snd_usb_audio *) mixer->chip;
- if (snd_BUG_ON(!chip))
- return -EINVAL;
-
- id = pval->bUnitID;
- validx = pval->validx;
-
- if (!pval->is_cached) {
- /* Read current value */
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- cur_val = value[0];
- pval->cached_value = cur_val;
- pval->is_cached = 1;
- }
- /* update value if needed */
- if (cur_val != new_val) {
- value[0] = new_val;
- value[1] = 0;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(chip->dev,
- usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- pval->cached_value = new_val;
- pval->is_cached = 1;
- changed = 1;
- }
-
- return changed;
-}
-
-static void kctl_private_value_free(struct snd_kcontrol *kctl)
-{
- kfree((void *)kctl->private_value);
+ kctl->private_value &= ~(0xff << 24);
+ kctl->private_value |= new_val << 24;
+ err = snd_ftu_eff_switch_update(list);
+ return err < 0 ? err : 1;
}
static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
@@ -902,33 +988,16 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
.get = snd_ftu_eff_switch_get,
.put = snd_ftu_eff_switch_put
};
-
+ struct usb_mixer_elem_list *list;
int err;
- struct snd_kcontrol *kctl;
- struct snd_ftu_eff_switch_priv_val *pval;
-
- pval = kzalloc(sizeof(*pval), GFP_KERNEL);
- if (!pval)
- return -ENOMEM;
-
- pval->cached_value = 0;
- pval->is_cached = 0;
- pval->mixer = mixer;
- pval->bUnitID = bUnitID;
- pval->validx = validx;
-
- template.private_value = (unsigned long) pval;
- kctl = snd_ctl_new1(&template, mixer->chip);
- if (!kctl) {
- kfree(pval);
- return -ENOMEM;
- }
- kctl->private_free = kctl_private_value_free;
- err = snd_ctl_add(mixer->chip->card, kctl);
+ err = add_single_ctl_with_resume(mixer, bUnitID,
+ snd_ftu_eff_switch_update,
+ &template, &list);
if (err < 0)
return err;
-
+ list->kctl->private_value = (validx << 8) | bUnitID;
+ snd_ftu_eff_switch_init(mixer, list->kctl);
return 0;
}
@@ -1110,7 +1179,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
int unitid = 12; /* SamleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
- cval = mixer->id_elems[unitid];
+ cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid];
if (cval) {
snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8,
@@ -1440,7 +1509,8 @@ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct snd_usb_audio *chip = list->mixer->chip;
int err;
struct usb_interface *iface;
struct usb_host_interface *alts;
@@ -1448,17 +1518,23 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
unsigned char data[3];
int rate;
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
ucontrol->value.iec958.status[2] = 0x00;
/* use known values for that card: interface#1 altsetting#1 */
- iface = usb_ifnum_to_if(mixer->chip->dev, 1);
+ iface = usb_ifnum_to_if(chip->dev, 1);
alts = &iface->altsetting[1];
ep = get_endpoint(alts, 0)->bEndpointAddress;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_rcvctrlpipe(mixer->chip->dev, 0),
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
@@ -1473,22 +1549,27 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
err = 0;
-end:
+ end:
+ up_read(&chip->shutdown_rwsem);
return err;
}
-static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int err;
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
u8 reg;
- unsigned long priv_backup = kcontrol->private_value;
+ int err;
- reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
- (ucontrol->value.iec958.status[0] & 0x0f);
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ reg = ((pval >> 4) & 0xf0) | (pval & 0x0f);
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1498,15 +1579,10 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
if (err < 0)
goto end;
- kcontrol->private_value &= 0xfffff0f0;
- kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
- kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
-
- reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
- 0xa0 : 0x20;
- reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20;
+ reg |= (pval >> 12) & 0x0f;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1516,16 +1592,36 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
if (err < 0)
goto end;
- kcontrol->private_value &= 0xffff0fff;
- kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
+ end:
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ unsigned int pval, pval_old;
+ int err;
+
+ pval = pval_old = kcontrol->private_value;
+ pval &= 0xfffff0f0;
+ pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
+ pval |= (ucontrol->value.iec958.status[0] & 0x0f);
+
+ pval &= 0xffff0fff;
+ pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
/* The frequency bits in AES3 cannot be set via register access. */
/* Silently ignore any bits from the request that cannot be set. */
- err = (priv_backup != kcontrol->private_value);
-end:
- return err;
+ if (pval == pval_old)
+ return 0;
+
+ kcontrol->private_value = pval;
+ err = snd_microii_spdif_default_update(list);
+ return err < 0 ? err : 1;
}
static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
@@ -1547,15 +1643,20 @@ static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct snd_usb_audio *chip = list->mixer->chip;
+ u8 reg = list->kctl->private_value;
int err;
- u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1563,15 +1664,27 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
NULL,
0);
- if (!err) {
- err = (reg != (kcontrol->private_value & 0x0ff));
- if (err)
- kcontrol->private_value = reg;
- }
-
+ end:
+ up_read(&chip->shutdown_rwsem);
return err;
}
+static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ u8 reg;
+ int err;
+
+ reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
+ if (reg != list->kctl->private_value)
+ return 0;
+
+ kcontrol->private_value = reg;
+ err = snd_microii_spdif_switch_update(list);
+ return err < 0 ? err : 1;
+}
+
static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1601,10 +1714,17 @@ static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
{
int err, i;
+ static usb_mixer_elem_resume_func_t resume_funcs[] = {
+ snd_microii_spdif_default_update,
+ NULL,
+ snd_microii_spdif_switch_update
+ };
for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
+ err = add_single_ctl_with_resume(mixer, 0,
+ resume_funcs[i],
+ &snd_microii_mixer_spdif[i],
+ NULL);
if (err < 0)
return err;
}
@@ -1661,6 +1781,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_microii_controls_create(mixer);
break;
+ case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */
+ err = snd_mbox1_create_sync_switch(mixer);
+ break;
+
case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
err = snd_nativeinstruments_create_mixer(mixer,
snd_nativeinstruments_ta6_mixers,
@@ -1677,6 +1801,14 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
/* detection is disabled in mixer_maps.c */
err = snd_create_std_mono_table(mixer, ebox44_table);
break;
+
+ case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */
+ case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */
+ case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */
+ case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */
+ case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */
+ err = snd_scarlett_controls_create(mixer);
+ break;
}
return err;
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
new file mode 100644
index 000000000000..9109652b88b9
--- /dev/null
+++ b/sound/usb/mixer_scarlett.c
@@ -0,0 +1,1004 @@
+/*
+ * Scarlett Driver for ALSA
+ *
+ * Copyright (c) 2013 by Tobias Hoffmann
+ * Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
+ * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
+ * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
+ *
+ * Many codes borrowed from audio.c by
+ * Alan Cox (alan at lxorguk.ukuu.org.uk)
+ * Thomas Sailer (sailer at ife.ee.ethz.ch)
+ *
+ * Code cleanup:
+ * David Henningsson <david.henningsson at canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Rewritten and extended to support more models, e.g. Scarlett 18i8.
+ *
+ * Auto-detection via UAC2 is not feasible to properly discover the vast
+ * majority of features. It's related to both Linux/ALSA's UAC2 as well as
+ * Focusrite's implementation of it. Eventually quirks may be sufficient but
+ * right now it's a major headache to work arount these things.
+ *
+ * NB. Neither the OSX nor the win driver provided by Focusrite performs
+ * discovery, they seem to operate the same as this driver.
+ */
+
+/* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
+ *
+ * The protocol was reverse engineered by looking at communication between
+ * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
+ * (firmware v305) using wireshark and usbmon in January 2013.
+ * Extended in July 2013.
+ *
+ * this mixer gives complete access to all features of the device:
+ * - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
+ * - select clock source
+ * - dynamic input to mixer-matrix assignment
+ * - 18 x 6 mixer-matrix gain stages
+ * - bus routing & volume control
+ * - automatic re-initialization on connect if device was power-cycled
+ *
+ * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
+ * wIndex
+ * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
+ * channel, data=Line/Inst (2bytes)
+ * pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
+ * ?? wValue=0x0803/04, ?? (2bytes)
+ * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
+ * Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
+ * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
+ * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
+ * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
+ * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
+ * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
+ * 0x3c Matrix Mixer gains, wValue=mixer-node data=gain(2bytes)
+ * ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
+ *
+ * USB reads: (i.e. actually issued by original software)
+ * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
+ * 0x29 wValue=0x0100 sample-rate(4bytes)
+ * wValue=0x0200 ?? 1byte (only once)
+ * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
+ *
+ * USB reads with bRequest = 0x03 = UAC2_CS_MEM
+ * 0x3c wValue=0x0002 1byte: sync status (locked=1)
+ * wValue=0x0000 18*2byte: peak meter (inputs)
+ * wValue=0x0001 8(?)*2byte: peak meter (mix)
+ * wValue=0x0003 6*2byte: peak meter (pcm/daw)
+ *
+ * USB write with bRequest = 0x03
+ * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
+ *
+ *
+ * <ditaa>
+ * /--------------\ 18chn 6chn /--------------\
+ * | Hardware in +--+-------\ /------+--+ ALSA PCM out |
+ * \--------------/ | | | | \--------------/
+ * | | | |
+ * | v v |
+ * | +---------------+ |
+ * | \ Matrix Mux / |
+ * | +-----+-----+ |
+ * | | |
+ * | | 18chn |
+ * | v |
+ * | +-----------+ |
+ * | | Mixer | |
+ * | | Matrix | |
+ * | | | |
+ * | | 18x6 Gain | |
+ * | | stages | |
+ * | +-----+-----+ |
+ * | | |
+ * | | |
+ * | 18chn | 6chn | 6chn
+ * v v v
+ * =========================
+ * +---------------+ +--—------------+
+ * \ Output Mux / \ Capture Mux /
+ * +-----+-----+ +-----+-----+
+ * | |
+ * | 6chn |
+ * v |
+ * +-------------+ |
+ * | Master Gain | |
+ * +------+------+ |
+ * | |
+ * | 6chn | 18chn
+ * | (3 stereo pairs) |
+ * /--------------\ | | /--------------\
+ * | Hardware out |<--/ \-->| ALSA PCM in |
+ * \--------------/ \--------------/
+ * </ditaa>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+#include "power.h"
+
+#include "mixer_scarlett.h"
+
+/* some gui mixers can't handle negative ctl values */
+#define SND_SCARLETT_LEVEL_BIAS 128
+#define SND_SCARLETT_MATRIX_IN_MAX 18
+#define SND_SCARLETT_CONTROLS_MAX 10
+#define SND_SCARLETT_OFFSETS_MAX 5
+
+enum {
+ SCARLETT_OUTPUTS,
+ SCARLETT_SWITCH_IMPEDANCE,
+ SCARLETT_SWITCH_PAD,
+};
+
+enum {
+ SCARLETT_OFFSET_PCM = 0,
+ SCARLETT_OFFSET_ANALOG = 1,
+ SCARLETT_OFFSET_SPDIF = 2,
+ SCARLETT_OFFSET_ADAT = 3,
+ SCARLETT_OFFSET_MIX = 4,
+};
+
+struct scarlett_mixer_elem_enum_info {
+ int start;
+ int len;
+ int offsets[SND_SCARLETT_OFFSETS_MAX];
+ char const * const *names;
+};
+
+struct scarlett_mixer_control {
+ unsigned char num;
+ unsigned char type;
+ const char *name;
+};
+
+struct scarlett_device_info {
+ int matrix_in;
+ int matrix_out;
+ int input_len;
+ int output_len;
+
+ struct scarlett_mixer_elem_enum_info opt_master;
+ struct scarlett_mixer_elem_enum_info opt_matrix;
+
+ /* initial values for matrix mux */
+ int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
+
+ int num_controls; /* number of items in controls */
+ const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
+};
+
+/********************** Enum Strings *************************/
+
+static const struct scarlett_mixer_elem_enum_info opt_pad = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "0dB", "-10dB"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_impedance = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "Line", "Hi-Z"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_clock = {
+ .start = 1,
+ .len = 3,
+ .offsets = {},
+ .names = (char const * const []){
+ "Internal", "SPDIF", "ADAT"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_sync = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "No Lock", "Locked"
+ }
+};
+
+static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = elem->channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, err, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &val);
+ if (err < 0)
+ return err;
+
+ val = !val; /* invert mute logic for mixer */
+ ucontrol->value.integer.value[i] = val;
+ }
+
+ return 0;
+}
+
+static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, changed = 0;
+ int err, oval, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[i];
+ val = !val;
+ if (oval != val) {
+ err = snd_usb_set_cur_mix_value(elem, i, i, val);
+ if (err < 0)
+ return err;
+
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
+{
+ struct usb_mixer_elem_info *elem =
+ container_of(list, struct usb_mixer_elem_info, head);
+ int i;
+
+ for (i = 0; i < elem->channels; i++)
+ if (elem->cached & (1 << i))
+ snd_usb_set_cur_mix_value(elem, i, i,
+ elem->cache_val[i]);
+ return 0;
+}
+
+static int scarlett_ctl_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = elem->channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)kctl->private_value +
+ SND_SCARLETT_LEVEL_BIAS;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int scarlett_ctl_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, err, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp(val / 256, -128, (int)kctl->private_value) +
+ SND_SCARLETT_LEVEL_BIAS;
+ ucontrol->value.integer.value[i] = val;
+ }
+
+ return 0;
+}
+
+static int scarlett_ctl_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, changed = 0;
+ int err, oval, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[i] -
+ SND_SCARLETT_LEVEL_BIAS;
+ val = val * 256;
+ if (oval != val) {
+ err = snd_usb_set_cur_mix_value(elem, i, i, val);
+ if (err < 0)
+ return err;
+
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+static void scarlett_generate_name(int i, char *dst, int offsets[])
+{
+ if (i > offsets[SCARLETT_OFFSET_MIX])
+ sprintf(dst, "Mix %c",
+ 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
+ else if (i > offsets[SCARLETT_OFFSET_ADAT])
+ sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
+ else if (i > offsets[SCARLETT_OFFSET_SPDIF])
+ sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
+ else if (i > offsets[SCARLETT_OFFSET_ANALOG])
+ sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
+ else if (i > offsets[SCARLETT_OFFSET_PCM])
+ sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
+ else
+ sprintf(dst, "Off");
+}
+
+static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ unsigned int items = opt->len;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = elem->channels;
+ uinfo->value.enumerated.items = items;
+
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
+
+ /* generate name dynamically based on item number and offset info */
+ scarlett_generate_name(uinfo->value.enumerated.item,
+ uinfo->value.enumerated.name,
+ opt->offsets);
+
+ return 0;
+}
+
+static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+
+ return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
+ (const char * const *)opt->names);
+}
+
+static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ int err, val;
+
+ err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp(val - opt->start, 0, opt->len-1);
+
+ ucontrol->value.enumerated.item[0] = val;
+
+ return 0;
+}
+
+static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ int err, oval, val;
+
+ err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[0];
+ val = val + opt->start;
+ if (val != oval) {
+ snd_usb_set_cur_mix_value(elem, 0, 0, val);
+ return 1;
+ }
+ return 0;
+}
+
+static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
+{
+ struct usb_mixer_elem_info *elem =
+ container_of(list, struct usb_mixer_elem_info, head);
+
+ if (elem->cached)
+ snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
+ return 0;
+}
+
+static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ unsigned char buf[2 * MAX_CHANNELS] = {0, };
+ int wValue = (elem->control << 8) | elem->idx_off;
+ int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
+ int err;
+
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_MEM,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+ USB_DIR_IN, wValue, idx, buf, elem->channels);
+ if (err < 0)
+ return err;
+
+ ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
+ return 0;
+}
+
+static struct snd_kcontrol_new usb_scarlett_ctl_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_switch_info,
+ .get = scarlett_ctl_switch_get,
+ .put = scarlett_ctl_switch_put,
+};
+
+static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
+
+static struct snd_kcontrol_new usb_scarlett_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "",
+ .info = scarlett_ctl_info,
+ .get = scarlett_ctl_get,
+ .put = scarlett_ctl_put,
+ .private_value = 6, /* max value */
+ .tlv = { .p = db_scale_scarlett_gain }
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_master = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "",
+ .info = scarlett_ctl_info,
+ .get = scarlett_ctl_get,
+ .put = scarlett_ctl_put,
+ .private_value = 6, /* max value */
+ .tlv = { .p = db_scale_scarlett_gain }
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_enum_info,
+ .get = scarlett_ctl_enum_get,
+ .put = scarlett_ctl_enum_put,
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_enum_dynamic_info,
+ .get = scarlett_ctl_enum_get,
+ .put = scarlett_ctl_enum_put,
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_sync = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "",
+ .info = scarlett_ctl_enum_info,
+ .get = scarlett_ctl_meter_get,
+};
+
+static int add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ usb_mixer_elem_resume_func_t resume,
+ int index, int offset, int num,
+ int val_type, int channels, const char *name,
+ const struct scarlett_mixer_elem_enum_info *opt,
+ struct usb_mixer_elem_info **elem_ret
+)
+{
+ struct snd_kcontrol *kctl;
+ struct usb_mixer_elem_info *elem;
+ int err;
+
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->head.mixer = mixer;
+ elem->head.resume = resume;
+ elem->control = offset;
+ elem->idx_off = num;
+ elem->head.id = index;
+ elem->val_type = val_type;
+
+ elem->channels = channels;
+
+ /* add scarlett_mixer_elem_enum_info struct */
+ elem->private_data = (void *)opt;
+
+ kctl = snd_ctl_new1(ncontrol, elem);
+ if (!kctl) {
+ kfree(elem);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+
+ strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+ err = snd_usb_mixer_add_control(&elem->head, kctl);
+ if (err < 0)
+ return err;
+
+ if (elem_ret)
+ *elem_ret = elem;
+
+ return 0;
+}
+
+static int add_output_ctls(struct usb_mixer_interface *mixer,
+ int index, const char *name,
+ const struct scarlett_device_info *info)
+{
+ int err;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ struct usb_mixer_elem_info *elem;
+
+ /* Add mute switch */
+ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
+ scarlett_ctl_resume, 0x0a, 0x01,
+ 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ /* Add volume control and initialize to 0 */
+ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
+ scarlett_ctl_resume, 0x0a, 0x02,
+ 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ /* Add L channel source playback enumeration */
+ snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x33, 0x00,
+ 2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
+ &elem);
+ if (err < 0)
+ return err;
+
+ /* Add R channel source playback enumeration */
+ snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x33, 0x00,
+ 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master,
+ &elem);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/********************** device-specific config *************************/
+
+/* untested... */
+static struct scarlett_device_info s6i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 6,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 27,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 19,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .num_controls = 0,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 12, 13, 14, 15, /* Analog -> 1..4 */
+ 16, 17, /* SPDIF -> 5,6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
+ 8, 9, 10, 11
+ }
+};
+
+/* untested... */
+static struct scarlett_device_info s8i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 6,
+ .input_len = 8,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 25,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 19,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .num_controls = 7,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 12, 13, 14, 15, /* Analog -> 1..4 */
+ 16, 17, /* SPDIF -> 5,6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
+ 8, 9, 10, 11
+ }
+};
+
+static struct scarlett_device_info s18i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 6,
+ .input_len = 18,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 31,
+ .offsets = {0, 6, 14, 16, 24},
+ .names = NULL,
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 25,
+ .offsets = {0, 6, 14, 16, 24},
+ .names = NULL,
+ },
+
+ .num_controls = 5,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */
+ 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */
+ 14, 15, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+static struct scarlett_device_info s18i8_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 18,
+ .output_len = 8,
+
+ .opt_master = {
+ .start = -1,
+ .len = 35,
+ .offsets = {0, 8, 16, 18, 26},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 27,
+ .offsets = {0, 8, 16, 18, 26},
+ .names = NULL
+ },
+
+ .num_controls = 10,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
+ { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
+ 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */
+ 16, 17, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+static struct scarlett_device_info s18i20_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 18,
+ .output_len = 20,
+
+ .opt_master = {
+ .start = -1,
+ .len = 47,
+ .offsets = {0, 20, 28, 30, 38},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 39,
+ .offsets = {0, 20, 28, 30, 38},
+ .names = NULL
+ },
+
+ .num_controls = 10,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
+ { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
+ { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
+ { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
+ { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
+ { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
+ { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
+ /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
+ },
+
+ .matrix_mux_init = {
+ 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
+ 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */
+ 28, 29, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+
+static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
+ struct scarlett_device_info *info)
+{
+ int i, err;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ const struct scarlett_mixer_control *ctl;
+ struct usb_mixer_elem_info *elem;
+
+ /* create master switch and playback volume */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
+ scarlett_ctl_resume, 0x0a, 0x01, 0,
+ USB_MIXER_S16, 1, "Master Playback Switch", NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
+ scarlett_ctl_resume, 0x0a, 0x02, 0,
+ USB_MIXER_S16, 1, "Master Playback Volume", NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ /* iterate through controls in info struct and create each one */
+ for (i = 0; i < info->num_controls; i++) {
+ ctl = &info->controls[i];
+
+ switch (ctl->type) {
+ case SCARLETT_OUTPUTS:
+ err = add_output_ctls(mixer, ctl->num, ctl->name, info);
+ if (err < 0)
+ return err;
+ break;
+ case SCARLETT_SWITCH_IMPEDANCE:
+ sprintf(mx, "Input %d Impedance Switch", ctl->num);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x01,
+ 0x09, ctl->num, USB_MIXER_S16, 1, mx,
+ &opt_impedance, &elem);
+ if (err < 0)
+ return err;
+ break;
+ case SCARLETT_SWITCH_PAD:
+ sprintf(mx, "Input %d Pad Switch", ctl->num);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x01,
+ 0x0b, ctl->num, USB_MIXER_S16, 1, mx,
+ &opt_pad, &elem);
+ if (err < 0)
+ return err;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Create and initialize a mixer for the Focusrite(R) Scarlett
+ */
+int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
+{
+ int err, i, o;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ struct scarlett_device_info *info;
+ struct usb_mixer_elem_info *elem;
+ static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
+
+ /* only use UAC_VERSION_2 */
+ if (!mixer->protocol)
+ return 0;
+
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x1235, 0x8012):
+ info = &s6i6_info;
+ break;
+ case USB_ID(0x1235, 0x8002):
+ info = &s8i6_info;
+ break;
+ case USB_ID(0x1235, 0x8004):
+ info = &s18i6_info;
+ break;
+ case USB_ID(0x1235, 0x8014):
+ info = &s18i8_info;
+ break;
+ case USB_ID(0x1235, 0x800c):
+ info = &s18i20_info;
+ break;
+ default: /* device not (yet) supported */
+ return -EINVAL;
+ }
+
+ /* generic function to create controls */
+ err = scarlett_controls_create_generic(mixer, info);
+ if (err < 0)
+ return err;
+
+ /* setup matrix controls */
+ for (i = 0; i < info->matrix_in; i++) {
+ snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
+ i+1);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x32,
+ 0x06, i, USB_MIXER_S16, 1, mx,
+ &info->opt_matrix, &elem);
+ if (err < 0)
+ return err;
+
+ for (o = 0; o < info->matrix_out; o++) {
+ sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
+ o+'A');
+ err = add_new_ctl(mixer, &usb_scarlett_ctl,
+ scarlett_ctl_resume, 0x3c, 0x00,
+ (i << 3) + (o & 0x07), USB_MIXER_S16,
+ 1, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ }
+ }
+
+ for (i = 0; i < info->input_len; i++) {
+ snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
+ i+1);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x34,
+ 0x00, i, USB_MIXER_S16, 1, mx,
+ &info->opt_master, &elem);
+ if (err < 0)
+ return err;
+ }
+
+ /* val_len == 1 needed here */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x28, 0x01, 0,
+ USB_MIXER_U8, 1, "Sample Clock Source",
+ &opt_clock, &elem);
+ if (err < 0)
+ return err;
+
+ /* val_len == 1 and UAC2_CS_MEM */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
+ USB_MIXER_U8, 1, "Sample Clock Sync Status",
+ &opt_sync, &elem);
+ if (err < 0)
+ return err;
+
+ /* initialize sampling rate to 48000 */
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
+ (0x29 << 8), sample_rate_buffer, 4);
+ if (err < 0)
+ return err;
+
+ return err;
+}
diff --git a/sound/usb/mixer_scarlett.h b/sound/usb/mixer_scarlett.h
new file mode 100644
index 000000000000..19c592ab0332
--- /dev/null
+++ b/sound/usb/mixer_scarlett.h
@@ -0,0 +1,6 @@
+#ifndef __USB_MIXER_SCARLETT_H
+#define __USB_MIXER_SCARLETT_H
+
+int snd_scarlett_controls_create(struct usb_mixer_interface *mixer);
+
+#endif /* __USB_MIXER_SCARLETT_H */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index c62a1659106d..0d8aba5fe1a8 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -482,6 +482,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
/* set interface */
if (subs->interface != fmt->iface ||
subs->altset_idx != fmt->altset_idx) {
+
+ err = snd_usb_select_mode_quirk(subs, fmt);
+ if (err < 0)
+ return -EIO;
+
err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
if (err < 0) {
dev_err(&dev->dev,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c657752a420c..73d2ba47cc31 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2667,57 +2667,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.type = QUIRK_MIDI_NOVATION
}
},
-{
- /*
- * Focusrite Scarlett 18i6
- *
- * Avoid mixer creation, which otherwise fails because some of
- * the interface descriptor subtypes for interface 0 are
- * unknown. That should be fixed or worked-around but this at
- * least allows the device to be used successfully with a DAW
- * and an external mixer. See comments below about other
- * ignored interfaces.
- */
- USB_DEVICE(0x1235, 0x8004),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Focusrite",
- .product_name = "Scarlett 18i6",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_COMPOSITE,
- .data = & (const struct snd_usb_audio_quirk[]) {
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 0,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 3,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 4,
- .type = QUIRK_MIDI_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Device Firmware Update) */
- .ifnum = 5,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = -1
- }
- }
- }
-},
/* Access Music devices */
{
@@ -2944,7 +2893,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = (const struct snd_usb_audio_quirk[]){
{
.ifnum = 0,
- .type = QUIRK_IGNORE_INTERFACE,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
},
{
.ifnum = 1,
@@ -2955,16 +2904,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.iface = 1,
.altsetting = 1,
.altset_idx = 1,
- .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .attributes = 0x4,
.endpoint = 0x02,
- .ep_attr = 0x01,
- .rates = SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
- .rate_min = 44100,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_SYNC,
+ .maxpacksize = 0x130,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
.rate_max = 48000,
- .nr_rates = 2,
+ .nr_rates = 1,
.rate_table = (unsigned int[]) {
- 44100, 48000
+ 48000
+ }
+ }
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = 0x4,
+ .endpoint = 0x81,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .maxpacksize = 0x130,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) {
+ 48000
}
}
},
@@ -2972,7 +2945,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.ifnum = -1
}
}
-
}
},
@@ -3203,6 +3175,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
/*
+ * ZOOM R16/24 in audio interface mode.
+ * Mixer descriptors are garbage, further quirks will be needed
+ * to make any of it functional, thus disabled for now.
+ * Playback stream appears to start and run fine but no sound
+ * is produced, so also disabled for now.
+ */
+ USB_DEVICE(0x1686, 0x00dd),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ /* Mixer */
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE,
+ },
+ {
+ /* Playback */
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE,
+ },
+ {
+ /* Capture */
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+ },
+ {
+ /* Midi */
+ .ifnum = 3,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ },
+ }
+ }
+},
+
+{
+ /*
* Some USB MIDI devices don't have an audio control interface,
* so we have to grab MIDI streaming interfaces here.
*/
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 60dfe0d28771..4dbfb3d18ee2 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -43,12 +43,13 @@
static int create_composite_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
- const struct snd_usb_audio_quirk *quirk)
+ const struct snd_usb_audio_quirk *quirk_comp)
{
int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
+ const struct snd_usb_audio_quirk *quirk;
int err;
- for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
+ for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
if (!iface)
continue;
@@ -58,9 +59,17 @@ static int create_composite_quirk(struct snd_usb_audio *chip,
err = snd_usb_create_quirk(chip, iface, driver, quirk);
if (err < 0)
return err;
- if (quirk->ifnum != probed_ifnum)
+ }
+
+ for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
+ iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
+ if (!iface)
+ continue;
+ if (quirk->ifnum != probed_ifnum &&
+ !usb_interface_claimed(iface))
usb_driver_claim_interface(driver, iface, (void *)-1L);
}
+
return 0;
}
@@ -1102,6 +1111,44 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
+
+/* Marantz/Denon USB DACs need a vendor cmd to switch
+ * between PCM and native DSD mode
+ */
+int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
+ struct audioformat *fmt)
+{
+ struct usb_device *dev = subs->dev;
+ int err;
+
+ switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+
+ /* First switch to alt set 0, otherwise the mode switch cmd
+ * will not be accepted by the DAC
+ */
+ err = usb_set_interface(dev, fmt->iface, 0);
+ if (err < 0)
+ return err;
+
+ mdelay(20); /* Delay needed after setting the interface */
+
+ switch (fmt->altsetting) {
+ case 2: /* DSD mode requested */
+ case 1: /* PCM mode requested */
+ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ fmt->altsetting - 1, 1, NULL, 0);
+ if (err < 0)
+ return err;
+ break;
+ }
+ mdelay(20);
+ }
+ return 0;
+}
+
void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
{
/*
@@ -1160,6 +1207,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
break;
}
}
+
+ /* Zoom R16/24 needs a tiny delay here, otherwise requests like
+ * get/set frequency return as failed despite actually succeeding.
+ */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1686) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == 0x00dd) &&
+ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ mdelay(1);
}
/*
@@ -1204,5 +1259,16 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
break;
}
+ /* Denon/Marantz devices with USB DAC functionality */
+ switch (chip->usb_id) {
+ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+ if (fp->altsetting == 2)
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+ break;
+ default:
+ break;
+ }
+
return 0;
}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 665e972a1b40..1b862386577d 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -31,6 +31,9 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value,
__u16 index, void *data, __u16 size);
+int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
+ struct audioformat *fmt);
+
u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes);
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index a63330dd1407..61d5dc2a3421 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -272,13 +272,8 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
for (s = 0; s < 4; s++) {
struct snd_usX2Y_substream *subs = usX2Y->subs[s];
if (subs) {
- if (atomic_read(&subs->state) >= state_PRERUNNING) {
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags);
- snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags);
- }
+ if (atomic_read(&subs->state) >= state_PRERUNNING)
+ snd_pcm_stop_xrun(subs->pcm_substream);
for (u = 0; u < NRURBS; u++) {
struct urb *urb = subs->urb[u];
if (NULL != urb)