summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/aoa/soundbus/i2sbus/control.c2
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c19
-rw-r--r--sound/aoa/soundbus/i2sbus/pcm.c7
-rw-r--r--sound/arm/aaci.c4
-rw-r--r--sound/atmel/ac97c.c51
-rw-r--r--sound/core/compress_offload.c26
-rw-r--r--sound/core/control.c68
-rw-r--r--sound/core/hwdep.c88
-rw-r--r--sound/core/init.c54
-rw-r--r--sound/core/memory.c4
-rw-r--r--sound/core/oss/pcm_oss.c6
-rw-r--r--sound/core/pcm.c70
-rw-r--r--sound/core/pcm_lib.c15
-rw-r--r--sound/core/pcm_memory.c2
-rw-r--r--sound/core/pcm_native.c23
-rw-r--r--sound/core/rawmidi.c47
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c6
-rw-r--r--sound/core/seq/seq_clientmgr.c17
-rw-r--r--sound/core/seq/seq_midi.c3
-rw-r--r--sound/core/seq/seq_midi_emul.c3
-rw-r--r--sound/core/seq/seq_ports.c9
-rw-r--r--sound/core/seq/seq_ports.h1
-rw-r--r--sound/core/sound.c116
-rw-r--r--sound/core/timer.c46
-rw-r--r--sound/drivers/aloop.c3
-rw-r--r--sound/drivers/dummy.c10
-rw-r--r--sound/drivers/ml403-ac97cr.c12
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c13
-rw-r--r--sound/drivers/mtpav.c12
-rw-r--r--sound/drivers/opl3/opl3_lib.c2
-rw-r--r--sound/drivers/opl3/opl3_midi.c11
-rw-r--r--sound/drivers/opl3/opl3_seq.c4
-rw-r--r--sound/drivers/opl4/opl4_lib.c2
-rw-r--r--sound/drivers/opl4/opl4_synth.c2
-rw-r--r--sound/drivers/pcsp/pcsp.c2
-rw-r--r--sound/drivers/pcsp/pcsp_input.c2
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c2
-rw-r--r--sound/drivers/serial-u16550.c11
-rw-r--r--sound/drivers/vx/vx_core.c2
-rw-r--r--sound/firewire/amdtp.c5
-rw-r--r--sound/firewire/bebob/bebob.c20
-rw-r--r--sound/firewire/bebob/bebob_stream.c16
-rw-r--r--sound/firewire/dice/dice-stream.c18
-rw-r--r--sound/firewire/dice/dice.c16
-rw-r--r--sound/firewire/fireworks/fireworks.c20
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c19
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c6
-rw-r--r--sound/firewire/oxfw/oxfw.c21
-rw-r--r--sound/i2c/other/ak4113.c36
-rw-r--r--sound/i2c/other/ak4114.c46
-rw-r--r--sound/i2c/other/ak4117.c10
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/isa/ad1816a/ad1816a.c5
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c11
-rw-r--r--sound/isa/ad1848/ad1848.c7
-rw-r--r--sound/isa/als100.c2
-rw-r--r--sound/isa/azt2320.c6
-rw-r--r--sound/isa/cmi8328.c4
-rw-r--r--sound/isa/cs423x/cs4231.c9
-rw-r--r--sound/isa/cs423x/cs4236.c13
-rw-r--r--sound/isa/cs423x/cs4236_lib.c11
-rw-r--r--sound/isa/es1688/es1688.c7
-rw-r--r--sound/isa/es1688/es1688_lib.c8
-rw-r--r--sound/isa/es18xx.c12
-rw-r--r--sound/isa/galaxy/galaxy.c4
-rw-r--r--sound/isa/gus/gus_instr.c172
-rw-r--r--sound/isa/gus/gus_pcm.c6
-rw-r--r--sound/isa/gus/gus_uart.c6
-rw-r--r--sound/isa/gus/gusclassic.c4
-rw-r--r--sound/isa/gus/gusextreme.c4
-rw-r--r--sound/isa/gus/gusmax.c8
-rw-r--r--sound/isa/gus/interwave.c14
-rw-r--r--sound/isa/msnd/msnd.c6
-rw-r--r--sound/isa/msnd/msnd.h2
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c5
-rw-r--r--sound/isa/opl3sa2.c7
-rw-r--r--sound/isa/opti9xx/miro.c14
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c15
-rw-r--r--sound/isa/sb/emu8000.c37
-rw-r--r--sound/isa/sb/emu8000_patch.c2
-rw-r--r--sound/isa/sb/emu8000_pcm.c10
-rw-r--r--sound/isa/sb/emu8000_synth.c3
-rw-r--r--sound/isa/sb/jazz16.c2
-rw-r--r--sound/isa/sb/sb16.c2
-rw-r--r--sound/isa/sb/sb16_main.c10
-rw-r--r--sound/isa/sb/sb8.c4
-rw-r--r--sound/isa/sb/sb8_main.c8
-rw-r--r--sound/isa/sb/sb8_midi.c20
-rw-r--r--sound/isa/sb/sb_common.c2
-rw-r--r--sound/isa/sb/sb_mixer.c2
-rw-r--r--sound/isa/sc6000.c2
-rw-r--r--sound/isa/sscape.c6
-rw-r--r--sound/isa/wavefront/wavefront.c4
-rw-r--r--sound/isa/wavefront/wavefront_fx.c2
-rw-r--r--sound/isa/wavefront/wavefront_midi.c14
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/isa/wss/wss_lib.c10
-rw-r--r--sound/oss/dmasound/dmasound_atari.c2
-rw-r--r--sound/oss/msnd_pinnacle.c4
-rw-r--r--sound/oss/pss.c2
-rw-r--r--sound/oss/swarm_cs4297a.c2
-rw-r--r--sound/oss/trix.c2
-rw-r--r--sound/parisc/harmony.c6
-rw-r--r--sound/pci/Kconfig9
-rw-r--r--sound/pci/ad1889.c18
-rw-r--r--sound/pci/ali5451/ali5451.c17
-rw-r--r--sound/pci/als300.c18
-rw-r--r--sound/pci/als4000.c17
-rw-r--r--sound/pci/asihpi/asihpi.c22
-rw-r--r--sound/pci/asihpi/hpi6000.c7
-rw-r--r--sound/pci/asihpi/hpioctl.c10
-rw-r--r--sound/pci/atiixp.c20
-rw-r--r--sound/pci/atiixp_modem.c20
-rw-r--r--sound/pci/au88x0/au88x0.h4
-rw-r--r--sound/pci/aw2/aw2-alsa.c4
-rw-r--r--sound/pci/aw2/aw2-saa7146.c2
-rw-r--r--sound/pci/azt3328.c17
-rw-r--r--sound/pci/bt87x.c5
-rw-r--r--sound/pci/ca0106/ca0106_main.c16
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c2
-rw-r--r--sound/pci/ca0106/ca0106_proc.c2
-rw-r--r--sound/pci/cmipci.c17
-rw-r--r--sound/pci/cs4281.c41
-rw-r--r--sound/pci/cs46xx/cs46xx.c10
-rw-r--r--sound/pci/cs46xx/cs46xx.h10
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c62
-rw-r--r--sound/pci/cs46xx/dsp_spos.c2
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c2
-rw-r--r--sound/pci/cs5530.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c18
-rw-r--r--sound/pci/ctxfi/cthw20k1.c14
-rw-r--r--sound/pci/ctxfi/cthw20k2.c17
-rw-r--r--sound/pci/echoaudio/darla20.c2
-rw-r--r--sound/pci/echoaudio/darla24.c2
-rw-r--r--sound/pci/echoaudio/echo3g.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.c11
-rw-r--r--sound/pci/echoaudio/gina20.c2
-rw-r--r--sound/pci/echoaudio/gina24.c2
-rw-r--r--sound/pci/echoaudio/indigo.c2
-rw-r--r--sound/pci/echoaudio/indigodj.c2
-rw-r--r--sound/pci/echoaudio/indigoio.c2
-rw-r--r--sound/pci/echoaudio/layla20.c2
-rw-r--r--sound/pci/echoaudio/layla24.c2
-rw-r--r--sound/pci/echoaudio/mia.c2
-rw-r--r--sound/pci/echoaudio/midi.c5
-rw-r--r--sound/pci/echoaudio/mona.c2
-rw-r--r--sound/pci/emu10k1/emu10k1.c27
-rw-r--r--sound/pci/emu10k1/emu10k1x.c19
-rw-r--r--sound/pci/emu10k1/emufx.c7
-rw-r--r--sound/pci/emu10k1/emupcm.c33
-rw-r--r--sound/pci/emu10k1/p16v.c14
-rw-r--r--sound/pci/ens1370.c54
-rw-r--r--sound/pci/es1938.c15
-rw-r--r--sound/pci/es1968.c18
-rw-r--r--sound/pci/fm801.c66
-rw-r--r--sound/pci/hda/Kconfig1
-rw-r--r--sound/pci/hda/hda_auto_parser.c18
-rw-r--r--sound/pci/hda/hda_controller.c13
-rw-r--r--sound/pci/hda/hda_hwdep.c7
-rw-r--r--sound/pci/hda/hda_i915.c154
-rw-r--r--sound/pci/hda/hda_i915.h37
-rw-r--r--sound/pci/hda/hda_intel.c78
-rw-r--r--sound/pci/hda/hda_intel.h71
-rw-r--r--sound/pci/hda/hda_priv.h2
-rw-r--r--sound/pci/hda/hda_tegra.c4
-rw-r--r--sound/pci/hda/patch_analog.c33
-rw-r--r--sound/pci/hda/patch_realtek.c96
-rw-r--r--sound/pci/hda/patch_sigmatel.c37
-rw-r--r--sound/pci/ice1712/ak4xxx.c2
-rw-r--r--sound/pci/ice1712/ice1712.c42
-rw-r--r--sound/pci/ice1712/ice1724.c16
-rw-r--r--sound/pci/ice1712/juli.c4
-rw-r--r--sound/pci/ice1712/wm8766.c16
-rw-r--r--sound/pci/ice1712/wm8766.h2
-rw-r--r--sound/pci/ice1712/wm8776.c15
-rw-r--r--sound/pci/ice1712/wm8776.h3
-rw-r--r--sound/pci/intel8x0.c17
-rw-r--r--sound/pci/intel8x0m.c14
-rw-r--r--sound/pci/korg1212/korg1212.c14
-rw-r--r--sound/pci/lola/lola.c6
-rw-r--r--sound/pci/maestro3.c17
-rw-r--r--sound/pci/mixart/mixart.c7
-rw-r--r--sound/pci/mixart/mixart_core.c2
-rw-r--r--sound/pci/mixart/mixart_hwdep.c2
-rw-r--r--sound/pci/nm256/nm256.c22
-rw-r--r--sound/pci/oxygen/Makefile2
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_io.c2
-rw-r--r--sound/pci/oxygen/oxygen_lib.c44
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c36
-rw-r--r--sound/pci/oxygen/oxygen_pcm.c53
-rw-r--r--sound/pci/oxygen/se6x.c160
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c2
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c2
-rw-r--r--sound/pci/riptide/riptide.c52
-rw-r--r--sound/pci/rme32.c5
-rw-r--r--sound/pci/rme96.c22
-rw-r--r--sound/pci/rme9652/hdsp.c20
-rw-r--r--sound/pci/rme9652/hdspm.c26
-rw-r--r--sound/pci/rme9652/rme9652.c5
-rw-r--r--sound/pci/sis7019.c18
-rw-r--r--sound/pci/sonicvibes.c10
-rw-r--r--sound/pci/trident/trident.c6
-rw-r--r--sound/pci/trident/trident.h6
-rw-r--r--sound/pci/trident/trident_main.c39
-rw-r--r--sound/pci/trident/trident_memory.c2
-rw-r--r--sound/pci/via82xx.c16
-rw-r--r--sound/pci/via82xx_modem.c17
-rw-r--r--sound/pci/vx222/vx222.c17
-rw-r--r--sound/pci/vx222/vx222_ops.c2
-rw-r--r--sound/pci/ymfpci/ymfpci.c8
-rw-r--r--sound/pci/ymfpci/ymfpci.h8
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c55
-rw-r--r--sound/ppc/awacs.c2
-rw-r--r--sound/ppc/beep.c2
-rw-r--r--sound/ppc/burgundy.c2
-rw-r--r--sound/ppc/pmac.c17
-rw-r--r--sound/ppc/snd_ps3.c4
-rw-r--r--sound/ppc/tumbler.c2
-rw-r--r--sound/sh/aica.c10
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c111
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.h1
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c68
-rw-r--r--sound/soc/cirrus/Kconfig2
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/adau1977.c17
-rw-r--r--sound/soc/codecs/cs35l32.c19
-rw-r--r--sound/soc/codecs/cs4265.c19
-rw-r--r--sound/soc/codecs/max98357a.c12
-rw-r--r--sound/soc/codecs/pcm512x.c178
-rw-r--r--sound/soc/codecs/rt5670.c7
-rw-r--r--sound/soc/codecs/rt5677.c32
-rw-r--r--sound/soc/codecs/sta32x.c6
-rw-r--r--sound/soc/codecs/sta350.c30
-rw-r--r--sound/soc/codecs/tas2552.c13
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c6
-rw-r--r--sound/soc/fsl/fsl_ssi.c11
-rw-r--r--sound/soc/generic/simple-card.c5
-rw-r--r--sound/soc/intel/broadwell.c4
-rw-r--r--sound/soc/intel/bytcr_dpcm_rt5640.c4
-rw-r--r--sound/soc/intel/cht_bsw_rt5645.c4
-rw-r--r--sound/soc/intel/cht_bsw_rt5672.c9
-rw-r--r--sound/soc/intel/haswell.c4
-rw-r--r--sound/soc/intel/sst-atom-controls.h2
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c28
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h9
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c68
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c60
-rw-r--r--sound/soc/intel/sst-mfld-platform.h1
-rw-r--r--sound/soc/intel/sst/sst.c138
-rw-r--r--sound/soc/intel/sst/sst.h12
-rw-r--r--sound/soc/intel/sst/sst_drv_interface.c65
-rw-r--r--sound/soc/intel/sst/sst_loader.c10
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c3
-rw-r--r--sound/soc/omap/omap-mcbsp.c11
-rw-r--r--sound/soc/omap/omap-pcm.c2
-rw-r--r--sound/soc/samsung/Kconfig10
-rw-r--r--sound/soc/sh/rcar/core.c4
-rw-r--r--sound/soc/soc-core.c16
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c2
-rw-r--r--sound/soc/soc-pcm.c27
-rw-r--r--sound/sparc/amd7930.c2
-rw-r--r--sound/synth/emux/emux.c10
-rw-r--r--sound/synth/emux/emux_hwdep.c2
-rw-r--r--sound/synth/emux/emux_oss.c2
-rw-r--r--sound/synth/emux/emux_synth.c6
-rw-r--r--sound/synth/emux/soundfont.c2
-rw-r--r--sound/usb/Kconfig2
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/clock.c5
-rw-r--r--sound/usb/line6/Kconfig42
-rw-r--r--sound/usb/line6/Makefile18
-rw-r--r--sound/usb/line6/capture.c275
-rw-r--r--sound/usb/line6/capture.h29
-rw-r--r--sound/usb/line6/driver.c672
-rw-r--r--sound/usb/line6/driver.h181
-rw-r--r--sound/usb/line6/midi.c292
-rw-r--r--sound/usb/line6/midi.h51
-rw-r--r--sound/usb/line6/midibuf.c252
-rw-r--r--sound/usb/line6/midibuf.h35
-rw-r--r--sound/usb/line6/pcm.c588
-rw-r--r--sound/usb/line6/pcm.h197
-rw-r--r--sound/usb/line6/playback.c429
-rw-r--r--sound/usb/line6/playback.h35
-rw-r--r--sound/usb/line6/pod.c584
-rw-r--r--sound/usb/line6/podhd.c192
-rw-r--r--sound/usb/line6/toneport.c580
-rw-r--r--sound/usb/line6/variax.c306
-rw-r--r--sound/usb/midi.c5
-rw-r--r--sound/usb/pcm.c9
-rw-r--r--sound/usb/quirks-table.h22
-rw-r--r--sound/usb/quirks.c8
-rw-r--r--sound/usb/quirks.h2
-rw-r--r--sound/usb/usx2y/usb_stream.h78
296 files changed, 7210 insertions, 2400 deletions
diff --git a/sound/aoa/soundbus/i2sbus/control.c b/sound/aoa/soundbus/i2sbus/control.c
index 4dc9b49c02cf..f4495decc699 100644
--- a/sound/aoa/soundbus/i2sbus/control.c
+++ b/sound/aoa/soundbus/i2sbus/control.c
@@ -9,8 +9,8 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/prom.h>
#include <asm/macio.h>
#include <asm/pmac_feature.h>
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 4e2b4fbf2496..b9737fae656a 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -74,10 +74,9 @@ static void i2sbus_release_dev(struct device *dev)
int i;
i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev);
-
- if (i2sdev->intfregs) iounmap(i2sdev->intfregs);
- if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
- if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
+ iounmap(i2sdev->intfregs);
+ iounmap(i2sdev->out.dbdma);
+ iounmap(i2sdev->in.dbdma);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
release_and_free_resource(i2sdev->allocated_resource[i]);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
@@ -318,9 +317,9 @@ static int i2sbus_add_dev(struct macio_dev *macio,
free_irq(dev->interrupts[i], dev);
free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring);
free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring);
- if (dev->intfregs) iounmap(dev->intfregs);
- if (dev->out.dbdma) iounmap(dev->out.dbdma);
- if (dev->in.dbdma) iounmap(dev->in.dbdma);
+ iounmap(dev->intfregs);
+ iounmap(dev->out.dbdma);
+ iounmap(dev->in.dbdma);
for (i=0;i<3;i++)
release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
@@ -381,10 +380,8 @@ static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state)
list_for_each_entry(i2sdev, &control->list, item) {
/* Notify Alsa */
- if (i2sdev->sound.pcm) {
- /* Suspend PCM streams */
- snd_pcm_suspend_all(i2sdev->sound.pcm);
- }
+ /* Suspend PCM streams */
+ snd_pcm_suspend_all(i2sdev->sound.pcm);
/* Notify codecs */
list_for_each_entry(cii, &i2sdev->sound.codec_list, list) {
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c
index 7b74a4ba75f8..053b09c79053 100644
--- a/sound/aoa/soundbus/i2sbus/pcm.c
+++ b/sound/aoa/soundbus/i2sbus/pcm.c
@@ -6,7 +6,7 @@
* GPL v2, can be found in COPYING.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -968,7 +968,6 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
printk(KERN_DEBUG "i2sbus: failed to create pcm\n");
goto out_put_ci_module;
}
- dev->pcm->dev = &dev->ofdev.dev;
}
/* ALSA yet again sucks.
@@ -988,6 +987,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
&i2sbus_playback_ops);
+ dev->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].dev.parent =
+ &dev->ofdev.dev;
i2sdev->out.created = 1;
}
@@ -1003,6 +1004,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
goto out_put_ci_module;
snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE,
&i2sbus_record_ops);
+ dev->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].dev.parent =
+ &dev->ofdev.dev;
i2sdev->in.created = 1;
}
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 0e83a73efb16..4140b1b95054 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -889,8 +889,8 @@ static int aaci_probe_ac97(struct aaci *aaci)
static void aaci_free_card(struct snd_card *card)
{
struct aaci *aaci = card->private_data;
- if (aaci->base)
- iounmap(aaci->base);
+
+ iounmap(aaci->base);
}
static struct aaci *aaci_init_card(struct amba_device *dev)
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 4f6b14d704f3..cf4cedf2b420 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -22,6 +22,9 @@
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/initval.h>
@@ -34,10 +37,10 @@
#include <linux/platform_data/dma-dw.h>
#include <linux/dma/dw.h>
+#ifdef CONFIG_AVR32
#include <mach/cpu.h>
-
-#ifdef CONFIG_ARCH_AT91
-#include <mach/hardware.h>
+#else
+#define cpu_is_at32ap7000() 0
#endif
#include "ac97c.h"
@@ -902,6 +905,40 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip)
}
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ac97c_dt_ids[] = {
+ { .compatible = "atmel,at91sam9263-ac97c", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids);
+
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+ struct ac97c_platform_data *pdata;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
+
+ if (!node) {
+ dev_err(dev, "Device does not have associated DT data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->reset_pin = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+
+ return pdata;
+}
+#else
+static struct ac97c_platform_data *atmel_ac97c_probe_dt(struct device *dev)
+{
+ dev_err(dev, "no platform data defined\n");
+ return ERR_PTR(-ENXIO);
+}
+#endif
+
static int atmel_ac97c_probe(struct platform_device *pdev)
{
struct snd_card *card;
@@ -922,10 +959,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
return -ENXIO;
}
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
- dev_dbg(&pdev->dev, "no platform data\n");
- return -ENXIO;
+ pdata = atmel_ac97c_probe_dt(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
}
irq = platform_get_irq(pdev, 0);
@@ -1204,6 +1242,7 @@ static struct platform_driver atmel_ac97c_driver = {
.driver = {
.name = "atmel_ac97c",
.pm = ATMEL_AC97C_PM_OPS,
+ .of_match_table = of_match_ptr(atmel_ac97c_dt_ids),
},
};
module_platform_driver(atmel_ac97c_driver);
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 89028fab64fd..b123c42e7dc8 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -868,12 +868,12 @@ static int snd_compress_dev_register(struct snd_device *device)
return -EBADFD;
compr = device->device_data;
- sprintf(str, "comprC%iD%i", compr->card->number, compr->device);
pr_debug("reg %s for device %s, direction %d\n", str, compr->name,
compr->direction);
/* register compressed device */
- ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
- compr->device, &snd_compr_file_ops, compr, str);
+ ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS,
+ compr->card, compr->device,
+ &snd_compr_file_ops, compr, &compr->dev);
if (ret < 0) {
pr_err("snd_register_device failed\n %d", ret);
return ret;
@@ -887,8 +887,16 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
struct snd_compr *compr;
compr = device->device_data;
- snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
- compr->device);
+ snd_unregister_device(&compr->dev);
+ return 0;
+}
+
+static int snd_compress_dev_free(struct snd_device *device)
+{
+ struct snd_compr *compr;
+
+ compr = device->device_data;
+ put_device(&compr->dev);
return 0;
}
@@ -903,7 +911,7 @@ int snd_compress_new(struct snd_card *card, int device,
int dirn, struct snd_compr *compr)
{
static struct snd_device_ops ops = {
- .dev_free = NULL,
+ .dev_free = snd_compress_dev_free,
.dev_register = snd_compress_dev_register,
.dev_disconnect = snd_compress_dev_disconnect,
};
@@ -911,6 +919,10 @@ int snd_compress_new(struct snd_card *card, int device,
compr->card = card;
compr->device = device;
compr->direction = dirn;
+
+ snd_device_initialize(&compr->dev, card);
+ dev_set_name(&compr->dev, "comprC%iD%i", card->number, device);
+
return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops);
}
EXPORT_SYMBOL_GPL(snd_compress_new);
@@ -948,7 +960,7 @@ int snd_compress_register(struct snd_compr *device)
{
int retval;
- if (device->name == NULL || device->dev == NULL || device->ops == NULL)
+ if (device->name == NULL || device->ops == NULL)
return -EINVAL;
pr_debug("Registering compressed device %s\n", device->name);
diff --git a/sound/core/control.c b/sound/core/control.c
index bb96a467e88d..35324a8e83c8 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -50,7 +50,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
- int err;
+ int i, err;
err = nonseekable_open(inode, file);
if (err < 0)
@@ -79,8 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ctl->change_sleep);
spin_lock_init(&ctl->read_lock);
ctl->card = card;
- ctl->prefer_pcm_subdevice = -1;
- ctl->prefer_rawmidi_subdevice = -1;
+ for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++)
+ ctl->preferred_subdevice[i] = -1;
ctl->pid = get_pid(task_pid(current));
file->private_data = ctl;
write_lock_irqsave(&card->ctl_files_rwlock, flags);
@@ -373,6 +373,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
+ id = kcontrol->id;
count = kcontrol->count;
up_write(&card->controls_rwsem);
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
@@ -439,6 +440,7 @@ add:
card->controls_count += kcontrol->count;
kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
+ id = kcontrol->id;
count = kcontrol->count;
up_write(&card->controls_rwsem);
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
@@ -1607,6 +1609,27 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
return fasync_helper(fd, file, on, &ctl->fasync);
}
+/* return the preferred subdevice number if already assigned;
+ * otherwise return -1
+ */
+int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
+{
+ struct snd_ctl_file *kctl;
+ int subdevice = -1;
+
+ read_lock(&card->ctl_files_rwlock);
+ list_for_each_entry(kctl, &card->ctl_files, list) {
+ if (kctl->pid == task_pid(current)) {
+ subdevice = kctl->preferred_subdevice[type];
+ if (subdevice != -1)
+ break;
+ }
+ }
+ read_unlock(&card->ctl_files_rwlock);
+ return subdevice;
+}
+EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
+
/*
* ioctl32 compat
*/
@@ -1639,19 +1662,9 @@ static const struct file_operations snd_ctl_f_ops =
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data;
- int err, cardnum;
- char name[16];
- if (snd_BUG_ON(!card))
- return -ENXIO;
- cardnum = card->number;
- if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
- return -ENXIO;
- sprintf(name, "controlC%i", cardnum);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
- &snd_ctl_f_ops, card, name)) < 0)
- return err;
- return 0;
+ return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
+ &snd_ctl_f_ops, card, &card->ctl_dev);
}
/*
@@ -1661,13 +1674,6 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
{
struct snd_card *card = device->device_data;
struct snd_ctl_file *ctl;
- int err, cardnum;
-
- if (snd_BUG_ON(!card))
- return -ENXIO;
- cardnum = card->number;
- if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
- return -ENXIO;
read_lock(&card->ctl_files_rwlock);
list_for_each_entry(ctl, &card->ctl_files, list) {
@@ -1676,10 +1682,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
}
read_unlock(&card->ctl_files_rwlock);
- if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
- card, -1)) < 0)
- return err;
- return 0;
+ return snd_unregister_device(&card->ctl_dev);
}
/*
@@ -1696,6 +1699,7 @@ static int snd_ctl_dev_free(struct snd_device *device)
snd_ctl_remove(card, control);
}
up_write(&card->controls_rwsem);
+ put_device(&card->ctl_dev);
return 0;
}
@@ -1710,10 +1714,20 @@ int snd_ctl_create(struct snd_card *card)
.dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect,
};
+ int err;
if (snd_BUG_ON(!card))
return -ENXIO;
- return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
+ if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS))
+ return -ENXIO;
+
+ snd_device_initialize(&card->ctl_dev, card);
+ dev_set_name(&card->ctl_dev, "controlC%d", card->number);
+
+ err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
+ if (err < 0)
+ put_device(&card->ctl_dev);
+ return err;
}
/*
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 69459e5f712e..84244a5143cf 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(snd_hwdep_devices);
static DEFINE_MUTEX(register_mutex);
-static int snd_hwdep_free(struct snd_hwdep *hwdep);
static int snd_hwdep_dev_free(struct snd_device *device);
static int snd_hwdep_dev_register(struct snd_device *device);
static int snd_hwdep_dev_disconnect(struct snd_device *device);
@@ -345,6 +344,11 @@ static const struct file_operations snd_hwdep_f_ops =
.mmap = snd_hwdep_mmap,
};
+static void release_hwdep_device(struct device *dev)
+{
+ kfree(container_of(dev, struct snd_hwdep, dev));
+}
+
/**
* snd_hwdep_new - create a new hwdep instance
* @card: the card instance
@@ -378,48 +382,49 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
dev_err(card->dev, "hwdep: cannot allocate\n");
return -ENOMEM;
}
+
+ init_waitqueue_head(&hwdep->open_wait);
+ mutex_init(&hwdep->open_mutex);
hwdep->card = card;
hwdep->device = device;
if (id)
strlcpy(hwdep->id, id, sizeof(hwdep->id));
+
+ snd_device_initialize(&hwdep->dev, card);
+ hwdep->dev.release = release_hwdep_device;
+ dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device);
#ifdef CONFIG_SND_OSSEMUL
hwdep->oss_type = -1;
#endif
- if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) {
- snd_hwdep_free(hwdep);
+
+ err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops);
+ if (err < 0) {
+ put_device(&hwdep->dev);
return err;
}
- init_waitqueue_head(&hwdep->open_wait);
- mutex_init(&hwdep->open_mutex);
+
if (rhwdep)
*rhwdep = hwdep;
return 0;
}
EXPORT_SYMBOL(snd_hwdep_new);
-static int snd_hwdep_free(struct snd_hwdep *hwdep)
+static int snd_hwdep_dev_free(struct snd_device *device)
{
+ struct snd_hwdep *hwdep = device->device_data;
if (!hwdep)
return 0;
if (hwdep->private_free)
hwdep->private_free(hwdep);
- kfree(hwdep);
+ put_device(&hwdep->dev);
return 0;
}
-static int snd_hwdep_dev_free(struct snd_device *device)
-{
- struct snd_hwdep *hwdep = device->device_data;
- return snd_hwdep_free(hwdep);
-}
-
static int snd_hwdep_dev_register(struct snd_device *device)
{
struct snd_hwdep *hwdep = device->device_data;
struct snd_card *card = hwdep->card;
- struct device *dev;
int err;
- char name[32];
mutex_lock(&register_mutex);
if (snd_hwdep_search(card, hwdep->device)) {
@@ -427,53 +432,30 @@ static int snd_hwdep_dev_register(struct snd_device *device)
return -EBUSY;
}
list_add_tail(&hwdep->list, &snd_hwdep_devices);
- sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
- dev = hwdep->dev;
- if (!dev)
- dev = snd_card_get_device_link(hwdep->card);
- err = snd_register_device_for_dev(SNDRV_DEVICE_TYPE_HWDEP,
- hwdep->card, hwdep->device,
- &snd_hwdep_f_ops, hwdep, name, dev);
+ err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
+ hwdep->card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep, &hwdep->dev);
if (err < 0) {
- dev_err(dev,
- "unable to register hardware dependent device %i:%i\n",
- card->number, hwdep->device);
+ dev_err(&hwdep->dev, "unable to register\n");
list_del(&hwdep->list);
mutex_unlock(&register_mutex);
return err;
}
- if (hwdep->groups) {
- struct device *d = snd_get_device(SNDRV_DEVICE_TYPE_HWDEP,
- hwdep->card, hwdep->device);
- if (d) {
- if (hwdep->private_data)
- dev_set_drvdata(d, hwdep->private_data);
- err = sysfs_create_groups(&d->kobj, hwdep->groups);
- if (err < 0)
- dev_warn(dev,
- "hwdep %d:%d: cannot create sysfs groups\n",
- card->number, hwdep->device);
- put_device(d);
- }
- }
-
#ifdef CONFIG_SND_OSSEMUL
hwdep->ossreg = 0;
if (hwdep->oss_type >= 0) {
- if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
- dev_warn(dev,
+ if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM &&
+ hwdep->device)
+ dev_warn(&hwdep->dev,
"only hwdep device 0 can be registered as OSS direct FM device!\n");
- } else {
- if (snd_register_oss_device(hwdep->oss_type,
- card, hwdep->device,
- &snd_hwdep_f_ops, hwdep) < 0) {
- dev_err(dev,
- "unable to register OSS compatibility device %i:%i\n",
- card->number, hwdep->device);
- } else
- hwdep->ossreg = 1;
- }
+ else if (snd_register_oss_device(hwdep->oss_type,
+ card, hwdep->device,
+ &snd_hwdep_f_ops, hwdep) < 0)
+ dev_warn(&hwdep->dev,
+ "unable to register OSS compatibility device\n");
+ else
+ hwdep->ossreg = 1;
}
#endif
mutex_unlock(&register_mutex);
@@ -497,7 +479,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
if (hwdep->ossreg)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
- snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
+ snd_unregister_device(&hwdep->dev);
list_del_init(&hwdep->list);
mutex_unlock(&hwdep->open_mutex);
mutex_unlock(&register_mutex);
diff --git a/sound/core/init.c b/sound/core/init.c
index 074875d68c15..35419054821c 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -157,8 +157,31 @@ static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
return mask; /* unchanged */
}
+/* the default release callback set in snd_device_initialize() below;
+ * this is just NOP for now, as almost all jobs are already done in
+ * dev_free callback of snd_device chain instead.
+ */
+static void default_release(struct device *dev)
+{
+}
+
+/**
+ * snd_device_initialize - Initialize struct device for sound devices
+ * @dev: device to initialize
+ * @card: card to assign, optional
+ */
+void snd_device_initialize(struct device *dev, struct snd_card *card)
+{
+ device_initialize(dev);
+ if (card)
+ dev->parent = &card->card_dev;
+ dev->class = sound_class;
+ dev->release = default_release;
+}
+EXPORT_SYMBOL_GPL(snd_device_initialize);
+
static int snd_card_do_free(struct snd_card *card);
-static const struct attribute_group *card_dev_attr_groups[];
+static const struct attribute_group card_dev_attr_group;
static void release_card_device(struct device *dev)
{
@@ -246,7 +269,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
card->card_dev.parent = parent;
card->card_dev.class = sound_class;
card->card_dev.release = release_card_device;
- card->card_dev.groups = card_dev_attr_groups;
+ card->card_dev.groups = card->dev_groups;
+ card->dev_groups[0] = &card_dev_attr_group;
err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
if (err < 0)
goto __error;
@@ -677,14 +701,32 @@ static struct attribute *card_dev_attrs[] = {
NULL
};
-static struct attribute_group card_dev_attr_group = {
+static const struct attribute_group card_dev_attr_group = {
.attrs = card_dev_attrs,
};
-static const struct attribute_group *card_dev_attr_groups[] = {
- &card_dev_attr_group,
- NULL
+/**
+ * snd_card_add_dev_attr - Append a new sysfs attribute group to card
+ * @card: card instance
+ * @group: attribute group to append
+ */
+int snd_card_add_dev_attr(struct snd_card *card,
+ const struct attribute_group *group)
+{
+ int i;
+
+ /* loop for (arraysize-1) here to keep NULL at the last entry */
+ for (i = 0; i < ARRAY_SIZE(card->dev_groups) - 1; i++) {
+ if (!card->dev_groups[i]) {
+ card->dev_groups[i] = group;
+ return 0;
+ }
+ }
+
+ dev_err(card->dev, "Too many groups assigned\n");
+ return -ENOSPC;
};
+EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);
/**
* snd_card_register - register the soundcard
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 36c0f1a2e189..4cd664efad77 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -21,8 +21,8 @@
*/
#include <linux/export.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
#include <sound/core.h>
/**
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index ada69d7a8d70..80423a4ccab6 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -719,7 +719,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
oss_buffer_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
- oss_buffer_size = 1 << ld2(oss_buffer_size);
+ oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
if (atomic_read(&substream->mmap_count)) {
if (oss_buffer_size > runtime->oss.mmap_bytes)
oss_buffer_size = runtime->oss.mmap_bytes;
@@ -755,14 +755,14 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
min_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
min_period_size *= oss_frame_size;
- min_period_size = 1 << (ld2(min_period_size - 1) + 1);
+ min_period_size = roundup_pow_of_two(min_period_size);
if (oss_period_size < min_period_size)
oss_period_size = min_period_size;
max_period_size = snd_pcm_plug_client_size(substream,
snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
max_period_size *= oss_frame_size;
- max_period_size = 1 << ld2(max_period_size);
+ max_period_size = rounddown_pow_of_two(max_period_size);
if (oss_period_size > max_period_size)
oss_period_size = max_period_size;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index cfc56c806964..0345e53a340c 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -161,7 +161,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
if (get_user(val, (int __user *)arg))
return -EFAULT;
- control->prefer_pcm_subdevice = val;
+ control->preferred_subdevice[SND_CTL_SUBDEV_PCM] = val;
return 0;
}
}
@@ -673,6 +673,8 @@ static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substrea
static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
#endif /* CONFIG_SND_VERBOSE_PROCFS */
+static const struct attribute_group *pcm_dev_attr_groups[];
+
/**
* snd_pcm_new_stream - create a new PCM stream
* @pcm: the pcm instance
@@ -698,7 +700,15 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
pstr->stream = stream;
pstr->pcm = pcm;
pstr->substream_count = substream_count;
- if (substream_count > 0 && !pcm->internal) {
+ if (!substream_count)
+ return 0;
+
+ snd_device_initialize(&pstr->dev, pcm->card);
+ pstr->dev.groups = pcm_dev_attr_groups;
+ dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
+ stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
+
+ if (!pcm->internal) {
err = snd_pcm_stream_proc_init(pstr);
if (err < 0) {
pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
@@ -868,6 +878,8 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
kfree(setup);
}
#endif
+ if (pstr->substream_count)
+ put_device(&pstr->dev);
}
static int snd_pcm_free(struct snd_pcm *pcm)
@@ -901,9 +913,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
struct snd_pcm_str * pstr;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
- struct snd_ctl_file *kctl;
struct snd_card *card;
- int prefer_subdevice = -1;
+ int prefer_subdevice;
size_t size;
if (snd_BUG_ON(!pcm || !rsubstream))
@@ -914,15 +925,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
return -ENODEV;
card = pcm->card;
- read_lock(&card->ctl_files_rwlock);
- list_for_each_entry(kctl, &card->ctl_files, list) {
- if (kctl->pid == task_pid(current)) {
- prefer_subdevice = kctl->prefer_pcm_subdevice;
- if (prefer_subdevice != -1)
- break;
- }
- }
- read_unlock(&card->ctl_files_rwlock);
+ prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
switch (stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1078,9 +1081,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
int cidx, err;
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
- char str[16];
struct snd_pcm *pcm;
- struct device *dev;
if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
@@ -1097,42 +1098,22 @@ static int snd_pcm_dev_register(struct snd_device *device)
continue;
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
- sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
case SNDRV_PCM_STREAM_CAPTURE:
- sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
- /* device pointer to use, pcm->dev takes precedence if
- * it is assigned, otherwise fall back to card's device
- * if possible */
- dev = pcm->dev;
- if (!dev)
- dev = snd_card_get_device_link(pcm->card);
/* register pcm */
- err = snd_register_device_for_dev(devtype, pcm->card,
- pcm->device,
- &snd_pcm_f_ops[cidx],
- pcm, str, dev);
+ err = snd_register_device(devtype, pcm->card, pcm->device,
+ &snd_pcm_f_ops[cidx], pcm,
+ &pcm->streams[cidx].dev);
if (err < 0) {
list_del(&pcm->list);
mutex_unlock(&register_mutex);
return err;
}
- dev = snd_get_device(devtype, pcm->card, pcm->device);
- if (dev) {
- err = sysfs_create_groups(&dev->kobj,
- pcm_dev_attr_groups);
- if (err < 0)
- dev_warn(dev,
- "pcm %d:%d: cannot create sysfs groups\n",
- pcm->card->number, pcm->device);
- put_device(dev);
- }
-
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
@@ -1149,7 +1130,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
struct snd_pcm *pcm = device->device_data;
struct snd_pcm_notify *notify;
struct snd_pcm_substream *substream;
- int cidx, devtype;
+ int cidx;
mutex_lock(&register_mutex);
if (list_empty(&pcm->list))
@@ -1172,16 +1153,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
notify->n_disconnect(pcm);
}
for (cidx = 0; cidx < 2; cidx++) {
- devtype = -1;
- switch (cidx) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
- break;
- case SNDRV_PCM_STREAM_CAPTURE:
- devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
- break;
- }
- snd_unregister_device(devtype, pcm->card, pcm->device);
+ snd_unregister_device(&pcm->streams[cidx].dev);
if (pcm->streams[cidx].chmap_kctl) {
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
pcm->streams[cidx].chmap_kctl = NULL;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 446c00bd908b..ffd656012ab8 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1384,8 +1384,14 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
int width = l & 0xffff;
unsigned int msbits = l >> 16;
struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
- if (snd_interval_single(i) && snd_interval_value(i) == width)
- params->msbits = msbits;
+
+ if (!snd_interval_single(i))
+ return 0;
+
+ if ((snd_interval_value(i) == width) ||
+ (width == 0 && snd_interval_value(i) > msbits))
+ params->msbits = min_not_zero(params->msbits, msbits);
+
return 0;
}
@@ -1396,6 +1402,11 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
* @width: sample bits width
* @msbits: msbits width
*
+ * This constraint will set the number of most significant bits (msbits) if a
+ * sample format with the specified width has been select. If width is set to 0
+ * the msbits will be set for any sample format with a width larger than the
+ * specified msbits.
+ *
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 54debc07f5cb..b45f6aa32264 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -19,7 +19,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 095d9572ad2b..279e24f61305 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -26,6 +26,7 @@
#include <linux/time.h>
#include <linux/pm_qos.h>
#include <linux/aio.h>
+#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -34,7 +35,6 @@
#include <sound/pcm_params.h>
#include <sound/timer.h>
#include <sound/minors.h>
-#include <asm/io.h>
/*
* Compatibility
@@ -420,7 +420,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
hw = &substream->runtime->hw;
if (!params->info) {
- params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER);
if (!hw_support_mmap(substream))
params->info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
@@ -719,8 +720,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
runtime->status->audio_tstamp;
goto _tstamp_end;
}
+ } else {
+ /* get tstamp only in fallback mode and only if enabled */
+ if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
+ snd_pcm_gettime(runtime, &status->tstamp);
}
- snd_pcm_gettime(runtime, &status->tstamp);
_tstamp_end:
status->appl_ptr = runtime->control->appl_ptr;
status->hw_ptr = runtime->status->hw_ptr;
@@ -806,7 +810,8 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
if (runtime->trigger_master == NULL)
return;
if (runtime->trigger_master == substream) {
- snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
+ if (!runtime->trigger_tstamp_latched)
+ snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
} else {
snd_pcm_trigger_tstamp(runtime->trigger_master);
runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
@@ -975,6 +980,7 @@ static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
!snd_pcm_playback_data(substream))
return -EPIPE;
+ runtime->trigger_tstamp_latched = false;
runtime->trigger_master = substream;
return 0;
}
@@ -1546,6 +1552,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
if (! snd_pcm_playback_empty(substream)) {
snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
+ } else {
+ runtime->status->state = SNDRV_PCM_STATE_SETUP;
}
break;
case SNDRV_PCM_STATE_RUNNING:
@@ -1566,6 +1574,13 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
snd_pcm_post_stop(substream, new_state);
}
}
+
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
+ runtime->trigger_master == substream &&
+ (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
+ return substream->ops->trigger(substream,
+ SNDRV_PCM_TRIGGER_DRAIN);
+
return 0;
}
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 6fc71a4c8a51..b5a748596fc4 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -57,11 +57,11 @@ static LIST_HEAD(snd_rawmidi_devices);
static DEFINE_MUTEX(register_mutex);
#define rmidi_err(rmidi, fmt, args...) \
- dev_err((rmidi)->card->dev, fmt, ##args)
+ dev_err(&(rmidi)->dev, fmt, ##args)
#define rmidi_warn(rmidi, fmt, args...) \
- dev_warn((rmidi)->card->dev, fmt, ##args)
+ dev_warn(&(rmidi)->dev, fmt, ##args)
#define rmidi_dbg(rmidi, fmt, args...) \
- dev_dbg((rmidi)->card->dev, fmt, ##args)
+ dev_dbg(&(rmidi)->dev, fmt, ##args)
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{
@@ -369,7 +369,6 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
struct snd_rawmidi *rmidi;
struct snd_rawmidi_file *rawmidi_file = NULL;
wait_queue_t wait;
- struct snd_ctl_file *kctl;
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
@@ -413,16 +412,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
init_waitqueue_entry(&wait, current);
add_wait_queue(&rmidi->open_wait, &wait);
while (1) {
- subdevice = -1;
- read_lock(&card->ctl_files_rwlock);
- list_for_each_entry(kctl, &card->ctl_files, list) {
- if (kctl->pid == task_pid(current)) {
- subdevice = kctl->prefer_rawmidi_subdevice;
- if (subdevice != -1)
- break;
- }
- }
- read_unlock(&card->ctl_files_rwlock);
+ subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_RAWMIDI);
err = rawmidi_open_priv(rmidi, subdevice, fflags, rawmidi_file);
if (err >= 0)
break;
@@ -862,7 +852,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
if (get_user(val, (int __user *)argp))
return -EFAULT;
- control->prefer_rawmidi_subdevice = val;
+ control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val;
return 0;
}
case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
@@ -1453,6 +1443,11 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
return 0;
}
+static void release_rawmidi_device(struct device *dev)
+{
+ kfree(container_of(dev, struct snd_rawmidi, dev));
+}
+
/**
* snd_rawmidi_new - create a rawmidi instance
* @card: the card instance
@@ -1497,6 +1492,11 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
if (id != NULL)
strlcpy(rmidi->id, id, sizeof(rmidi->id));
+
+ snd_device_initialize(&rmidi->dev, card);
+ rmidi->dev.release = release_rawmidi_device;
+ dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
+
if ((err = snd_rawmidi_alloc_substreams(rmidi,
&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
SNDRV_RAWMIDI_STREAM_INPUT,
@@ -1548,7 +1548,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
if (rmidi->private_free)
rmidi->private_free(rmidi);
- kfree(rmidi);
+ put_device(&rmidi->dev);
return 0;
}
@@ -1581,19 +1581,18 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
return -EBUSY;
}
list_add_tail(&rmidi->list, &snd_rawmidi_devices);
- sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
- rmidi->card, rmidi->device,
- &snd_rawmidi_f_ops, rmidi, name)) < 0) {
- rmidi_err(rmidi, "unable to register rawmidi device %i:%i\n",
- rmidi->card->number, rmidi->device);
+ err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
+ rmidi->card, rmidi->device,
+ &snd_rawmidi_f_ops, rmidi, &rmidi->dev);
+ if (err < 0) {
+ rmidi_err(rmidi, "unable to register\n");
list_del(&rmidi->list);
mutex_unlock(&register_mutex);
return err;
}
if (rmidi->ops && rmidi->ops->dev_register &&
(err = rmidi->ops->dev_register(rmidi)) < 0) {
- snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+ snd_unregister_device(&rmidi->dev);
list_del(&rmidi->list);
mutex_unlock(&register_mutex);
return err;
@@ -1681,7 +1680,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
rmidi->ossreg = 0;
}
#endif /* CONFIG_SND_OSSEMUL */
- snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+ snd_unregister_device(&rmidi->dev);
mutex_unlock(&rmidi->open_mutex);
mutex_unlock(&register_mutex);
return 0;
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 3a4569669efa..e79cc44b1394 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -237,8 +237,7 @@ snd_seq_oss_midi_check_exit_port(int client, int port)
spin_unlock_irqrestore(&register_lock, flags);
snd_use_lock_free(&mdev->use_lock);
snd_use_lock_sync(&mdev->use_lock);
- if (mdev->coder)
- snd_midi_event_free(mdev->coder);
+ snd_midi_event_free(mdev->coder);
kfree(mdev);
}
spin_lock_irqsave(&register_lock, flags);
@@ -265,8 +264,7 @@ snd_seq_oss_midi_clear_all(void)
spin_lock_irqsave(&register_lock, flags);
for (i = 0; i < max_midi_devs; i++) {
if ((mdev = midi_devs[i]) != NULL) {
- if (mdev->coder)
- snd_midi_event_free(mdev->coder);
+ snd_midi_event_free(mdev->coder);
kfree(mdev);
midi_devs[i] = NULL;
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 225c73152ee9..48287651ac77 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1133,7 +1133,7 @@ static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void __user
/* fill the info fields */
info.queues = SNDRV_SEQ_MAX_QUEUES;
info.clients = SNDRV_SEQ_MAX_CLIENTS;
- info.ports = 256; /* fixed limit */
+ info.ports = SNDRV_SEQ_MAX_PORTS;
info.channels = 256; /* fixed limit */
info.cur_clients = client_usage.cur;
info.cur_queues = snd_seq_queue_get_cur_queues();
@@ -1279,7 +1279,6 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client,
port->owner = callback->owner;
port->private_data = callback->private_data;
port->private_free = callback->private_free;
- port->callback_all = callback->callback_all;
port->event_input = callback->event_input;
port->c_src.open = callback->subscribe;
port->c_src.close = callback->unsubscribe;
@@ -2571,6 +2570,8 @@ static const struct file_operations snd_seq_f_ops =
.compat_ioctl = snd_seq_ioctl_compat,
};
+static struct device seq_dev;
+
/*
* register sequencer device
*/
@@ -2578,12 +2579,17 @@ int __init snd_sequencer_device_init(void)
{
int err;
+ snd_device_initialize(&seq_dev, NULL);
+ dev_set_name(&seq_dev, "seq");
+
if (mutex_lock_interruptible(&register_mutex))
return -ERESTARTSYS;
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
- &snd_seq_f_ops, NULL, "seq")) < 0) {
+ err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
+ &snd_seq_f_ops, NULL, &seq_dev);
+ if (err < 0) {
mutex_unlock(&register_mutex);
+ put_device(&seq_dev);
return err;
}
@@ -2599,5 +2605,6 @@ int __init snd_sequencer_device_init(void)
*/
void __exit snd_sequencer_device_done(void)
{
- snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);
+ snd_unregister_device(&seq_dev);
+ put_device(&seq_dev);
}
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index a1fd77af6059..68fec776da26 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -268,8 +268,7 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
}
- if (msynth->parser)
- snd_midi_event_free(msynth->parser);
+ snd_midi_event_free(msynth->parser);
}
/* register new midi synth port */
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 9b6470cdcf24..7ba937399ac7 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -269,6 +269,9 @@ do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chse
{
int i;
+ if (control >= ARRAY_SIZE(chan->control))
+ return;
+
/* Switches */
if ((control >=64 && control <=69) || (control >= 80 && control <= 83)) {
/* These are all switches; either off or on so set to 0 or 127 */
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 794a341bf0e5..46ff593f618d 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -134,7 +134,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
if (snd_BUG_ON(!client))
return NULL;
- if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
+ if (client->num_ports >= SNDRV_SEQ_MAX_PORTS) {
pr_warn("ALSA: seq: too many ports for client %d\n", client->number);
return NULL;
}
@@ -411,9 +411,6 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
* invoked.
* This feature is useful if these callbacks are associated with
* initialization or termination of devices (see seq_midi.c).
- *
- * If callback_all option is set, the callback function is invoked
- * at each connection/disconnection.
*/
static int subscribe_port(struct snd_seq_client *client,
@@ -427,7 +424,7 @@ static int subscribe_port(struct snd_seq_client *client,
if (!try_module_get(port->owner))
return -EFAULT;
grp->count++;
- if (grp->open && (port->callback_all || grp->count == 1)) {
+ if (grp->open && grp->count == 1) {
err = grp->open(port->private_data, info);
if (err < 0) {
module_put(port->owner);
@@ -452,7 +449,7 @@ static int unsubscribe_port(struct snd_seq_client *client,
if (! grp->count)
return -EINVAL;
grp->count--;
- if (grp->close && (port->callback_all || grp->count == 0))
+ if (grp->close && grp->count == 0)
err = grp->close(port->private_data, info);
if (send_ack && client->type == USER_CLIENT)
snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index 9d7117118ba4..26bd71f36c41 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -73,7 +73,6 @@ struct snd_seq_client_port {
int atomic, int hop);
void (*private_free)(void *private_data);
void *private_data;
- unsigned int callback_all : 1;
unsigned int closing : 1;
unsigned int timestamping: 1;
unsigned int time_real: 1;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index f1333060bf1c..185cec01ee25 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -242,30 +242,30 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
#endif
/**
- * snd_register_device_for_dev - Register the ALSA device file for the card
+ * snd_register_device - Register the ALSA device file for the card
* @type: the device type, SNDRV_DEVICE_TYPE_XXX
* @card: the card instance
* @dev: the device index
* @f_ops: the file operations
* @private_data: user pointer for f_ops->open()
- * @name: the device file name
- * @device: the &struct device to link this new device to
+ * @device: the device to register
*
* Registers an ALSA device file for the given card.
* The operators have to be set in reg parameter.
*
* Return: Zero if successful, or a negative error code on failure.
*/
-int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
- const struct file_operations *f_ops,
- void *private_data,
- const char *name, struct device *device)
+int snd_register_device(int type, struct snd_card *card, int dev,
+ const struct file_operations *f_ops,
+ void *private_data, struct device *device)
{
int minor;
+ int err = 0;
struct snd_minor *preg;
- if (snd_BUG_ON(!name))
+ if (snd_BUG_ON(!device))
return -EINVAL;
+
preg = kmalloc(sizeof *preg, GFP_KERNEL);
if (preg == NULL)
return -ENOMEM;
@@ -284,102 +284,56 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
minor = -EBUSY;
#endif
if (minor < 0) {
- mutex_unlock(&sound_mutex);
- kfree(preg);
- return minor;
- }
- snd_minors[minor] = preg;
- preg->dev = device_create(sound_class, device, MKDEV(major, minor),
- private_data, "%s", name);
- if (IS_ERR(preg->dev)) {
- snd_minors[minor] = NULL;
- mutex_unlock(&sound_mutex);
- minor = PTR_ERR(preg->dev);
- kfree(preg);
- return minor;
+ err = minor;
+ goto error;
}
- mutex_unlock(&sound_mutex);
- return 0;
-}
-
-EXPORT_SYMBOL(snd_register_device_for_dev);
-
-/* find the matching minor record
- * return the index of snd_minor, or -1 if not found
- */
-static int find_snd_minor(int type, struct snd_card *card, int dev)
-{
- int cardnum, minor;
- struct snd_minor *mptr;
+ preg->dev = device;
+ device->devt = MKDEV(major, minor);
+ err = device_add(device);
+ if (err < 0)
+ goto error;
- cardnum = card ? card->number : -1;
- for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
- if ((mptr = snd_minors[minor]) != NULL &&
- mptr->type == type &&
- mptr->card == cardnum &&
- mptr->device == dev)
- return minor;
- return -1;
+ snd_minors[minor] = preg;
+ error:
+ mutex_unlock(&sound_mutex);
+ if (err < 0)
+ kfree(preg);
+ return err;
}
+EXPORT_SYMBOL(snd_register_device);
/**
* snd_unregister_device - unregister the device on the given card
- * @type: the device type, SNDRV_DEVICE_TYPE_XXX
- * @card: the card instance
- * @dev: the device index
+ * @dev: the device instance
*
* Unregisters the device file already registered via
* snd_register_device().
*
* Return: Zero if successful, or a negative error code on failure.
*/
-int snd_unregister_device(int type, struct snd_card *card, int dev)
+int snd_unregister_device(struct device *dev)
{
int minor;
+ struct snd_minor *preg;
mutex_lock(&sound_mutex);
- minor = find_snd_minor(type, card, dev);
- if (minor < 0) {
- mutex_unlock(&sound_mutex);
- return -EINVAL;
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
+ preg = snd_minors[minor];
+ if (preg && preg->dev == dev) {
+ snd_minors[minor] = NULL;
+ device_del(dev);
+ kfree(preg);
+ break;
+ }
}
-
- device_destroy(sound_class, MKDEV(major, minor));
-
- kfree(snd_minors[minor]);
- snd_minors[minor] = NULL;
mutex_unlock(&sound_mutex);
+ if (minor >= ARRAY_SIZE(snd_minors))
+ return -ENOENT;
return 0;
}
-
EXPORT_SYMBOL(snd_unregister_device);
-/**
- * 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)
-{
- int minor;
- struct device *d = NULL;
-
- mutex_lock(&sound_mutex);
- minor = find_snd_minor(type, card, dev);
- if (minor >= 0) {
- d = snd_minors[minor]->dev;
- if (d)
- get_device(d);
- }
- mutex_unlock(&sound_mutex);
- return d;
-}
-EXPORT_SYMBOL(snd_get_device);
-
#ifdef CONFIG_PROC_FS
/*
* INFO PART
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 777a45e08e53..490b489d713d 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1030,9 +1030,7 @@ static int snd_timer_register_system(void)
snd_timer_free(timer);
return -ENOMEM;
}
- init_timer(&priv->tlist);
- priv->tlist.function = snd_timer_s_function;
- priv->tlist.data = (unsigned long) timer;
+ setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
timer->private_data = priv;
timer->private_free = snd_timer_free_system;
return snd_timer_global_register(timer);
@@ -1942,6 +1940,17 @@ static const struct file_operations snd_timer_f_ops =
.fasync = snd_timer_user_fasync,
};
+/* unregister the system timer */
+static void snd_timer_free_all(void)
+{
+ struct snd_timer *timer, *n;
+
+ list_for_each_entry_safe(timer, n, &snd_timer_list, device_list)
+ snd_timer_free(timer);
+}
+
+static struct device timer_dev;
+
/*
* ENTRY functions
*/
@@ -1950,30 +1959,39 @@ static int __init alsa_timer_init(void)
{
int err;
+ snd_device_initialize(&timer_dev, NULL);
+ dev_set_name(&timer_dev, "timer");
+
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
"system timer");
#endif
- if ((err = snd_timer_register_system()) < 0)
+ err = snd_timer_register_system();
+ if (err < 0) {
pr_err("ALSA: unable to register system timer (%i)\n", err);
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
- &snd_timer_f_ops, NULL, "timer")) < 0)
+ put_device(&timer_dev);
+ return err;
+ }
+
+ err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
+ &snd_timer_f_ops, NULL, &timer_dev);
+ if (err < 0) {
pr_err("ALSA: unable to register timer device (%i)\n", err);
+ snd_timer_free_all();
+ put_device(&timer_dev);
+ return err;
+ }
+
snd_timer_proc_init();
return 0;
}
static void __exit alsa_timer_exit(void)
{
- struct list_head *p, *n;
-
- snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);
- /* unregister the system timer */
- list_for_each_safe(p, n, &snd_timer_list) {
- struct snd_timer *timer = list_entry(p, struct snd_timer, device_list);
- snd_timer_free(timer);
- }
+ snd_unregister_device(&timer_dev);
+ snd_timer_free_all();
+ put_device(&timer_dev);
snd_timer_proc_done();
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 7ea53399404d..7f9126efc1e5 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -181,8 +181,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)
}
tick = dpcm->period_size_frac - dpcm->irq_pos;
tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
- dpcm->timer.expires = jiffies + tick;
- add_timer(&dpcm->timer);
+ mod_timer(&dpcm->timer, jiffies + tick);
}
/* call in cable->lock */
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 5d0dfb787cec..d11baaf0f0b4 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -245,9 +245,8 @@ struct dummy_systimer_pcm {
static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
{
- dpcm->timer.expires = jiffies +
- (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
- add_timer(&dpcm->timer);
+ mod_timer(&dpcm->timer, jiffies +
+ (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
}
static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
@@ -340,9 +339,8 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream)
if (!dpcm)
return -ENOMEM;
substream->runtime->private_data = dpcm;
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = dummy_systimer_callback;
+ setup_timer(&dpcm->timer, dummy_systimer_callback,
+ (unsigned long) dpcm);
spin_lock_init(&dpcm->lock);
dpcm->substream = substream;
return 0;
diff --git a/sound/drivers/ml403-ac97cr.c b/sound/drivers/ml403-ac97cr.c
index bcca825a1c8d..bdcb5721393b 100644
--- a/sound/drivers/ml403-ac97cr.c
+++ b/sound/drivers/ml403-ac97cr.c
@@ -1094,8 +1094,7 @@ static int snd_ml403_ac97cr_free(struct snd_ml403_ac97cr *ml403_ac97cr)
if (ml403_ac97cr->capture_irq >= 0)
free_irq(ml403_ac97cr->capture_irq, ml403_ac97cr);
/* give back "port" */
- if (ml403_ac97cr->port != NULL)
- iounmap(ml403_ac97cr->port);
+ iounmap(ml403_ac97cr->port);
kfree(ml403_ac97cr);
PDEBUG(INIT_INFO, "free(): (done)\n");
return 0;
@@ -1238,14 +1237,11 @@ snd_ml403_ac97cr_mixer(struct snd_ml403_ac97cr *ml403_ac97cr)
}
static int
-snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
- struct snd_pcm **rpcm)
+snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ml403_ac97cr->card, "ML403AC97CR/1", device, 1, 1,
&pcm);
if (err < 0)
@@ -1263,8 +1259,6 @@ snd_ml403_ac97cr_pcm(struct snd_ml403_ac97cr *ml403_ac97cr, int device,
snd_dma_continuous_data(GFP_KERNEL),
64 * 1024,
128 * 1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1298,7 +1292,7 @@ static int snd_ml403_ac97cr_probe(struct platform_device *pfdev)
return err;
}
PDEBUG(INIT_INFO, "probe(): mixer done\n");
- err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0, NULL);
+ err = snd_ml403_ac97cr_pcm(ml403_ac97cr, 0);
if (err < 0) {
snd_card_free(card);
return err;
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index e3a90d043f03..776596b5ee05 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -28,7 +28,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -176,8 +176,7 @@ static void snd_mpu401_uart_timer(unsigned long data)
spin_lock_irqsave(&mpu->timer_lock, flags);
/*mpu->mode |= MPU401_MODE_TIMER;*/
- mpu->timer.expires = 1 + jiffies;
- add_timer(&mpu->timer);
+ mod_timer(&mpu->timer, 1 + jiffies);
spin_unlock_irqrestore(&mpu->timer_lock, flags);
if (mpu->rmidi)
_snd_mpu401_uart_interrupt(mpu);
@@ -192,11 +191,9 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input)
spin_lock_irqsave (&mpu->timer_lock, flags);
if (mpu->timer_invoked == 0) {
- init_timer(&mpu->timer);
- mpu->timer.data = (unsigned long)mpu;
- mpu->timer.function = snd_mpu401_uart_timer;
- mpu->timer.expires = 1 + jiffies;
- add_timer(&mpu->timer);
+ setup_timer(&mpu->timer, snd_mpu401_uart_timer,
+ (unsigned long)mpu);
+ mod_timer(&mpu->timer, 1 + jiffies);
}
mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER :
MPU401_MODE_OUTPUT_TIMER;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 15769447688f..30e8a1d5bc87 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -414,8 +414,7 @@ static void snd_mtpav_output_timer(unsigned long data)
spin_lock_irqsave(&chip->spinlock, flags);
/* reprogram timer */
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
/* process each port */
for (p = 0; p <= chip->num_ports * 2 + MTPAV_PIDX_BROADCAST; p++) {
struct mtpav_port *portp = &chip->ports[p];
@@ -428,8 +427,7 @@ static void snd_mtpav_output_timer(unsigned long data)
/* spinlock held! */
static void snd_mtpav_add_output_timer(struct mtpav *chip)
{
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
/* spinlock held! */
@@ -704,15 +702,13 @@ static int snd_mtpav_probe(struct platform_device *dev)
mtp_card = card->private_data;
spin_lock_init(&mtp_card->spinlock);
- init_timer(&mtp_card->timer);
mtp_card->card = card;
mtp_card->irq = -1;
mtp_card->share_irq = 0;
mtp_card->inmidistate = 0;
mtp_card->outmidihwport = 0xffffffff;
- init_timer(&mtp_card->timer);
- mtp_card->timer.function = snd_mtpav_output_timer;
- mtp_card->timer.data = (unsigned long) mtp_card;
+ setup_timer(&mtp_card->timer, snd_mtpav_output_timer,
+ (unsigned long) mtp_card);
card->private_free = snd_mtpav_free;
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index f66af5884c40..369cef212ea9 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -24,7 +24,7 @@
*/
#include <sound/opl3.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 6c6d09a51f42..f62780ed64ad 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -258,12 +258,10 @@ void snd_opl3_timer_func(unsigned long data)
spin_unlock_irqrestore(&opl3->voice_lock, flags);
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
- if (again) {
- opl3->tlist.expires = jiffies + 1; /* invoke again */
- add_timer(&opl3->tlist);
- } else {
+ if (again)
+ mod_timer(&opl3->tlist, jiffies + 1); /* invoke again */
+ else
opl3->sys_timer_status = 0;
- }
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
}
@@ -275,8 +273,7 @@ static void snd_opl3_start_timer(struct snd_opl3 *opl3)
unsigned long flags;
spin_lock_irqsave(&opl3->sys_timer_lock, flags);
if (! opl3->sys_timer_status) {
- opl3->tlist.expires = jiffies + 1;
- add_timer(&opl3->tlist);
+ mod_timer(&opl3->tlist, jiffies + 1);
opl3->sys_timer_status = 1;
}
spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index 68399538e435..a9f618e06a22 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -247,9 +247,7 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
}
/* setup system timer */
- init_timer(&opl3->tlist);
- opl3->tlist.function = snd_opl3_timer_func;
- opl3->tlist.data = (unsigned long) opl3;
+ setup_timer(&opl3->tlist, snd_opl3_timer_func, (unsigned long) opl3);
spin_lock_init(&opl3->sys_timer_lock);
opl3->sys_timer_status = 0;
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index b953fb4aa298..3b0ee42a5343 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("OPL4 driver");
diff --git a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c
index 4b91adc0238c..7bc1e58c95aa 100644
--- a/sound/drivers/opl4/opl4_synth.c
+++ b/sound/drivers/opl4/opl4_synth.c
@@ -33,7 +33,7 @@
#include "opl4_local.h"
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/asoundef.h>
/* GM2 controllers */
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 2adc7548ffca..d9647bd84d0f 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -13,7 +13,7 @@
#include <sound/pcm.h>
#include <linux/input.h>
#include <linux/delay.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include "pcsp_input.h"
#include "pcsp.h"
diff --git a/sound/drivers/pcsp/pcsp_input.c b/sound/drivers/pcsp/pcsp_input.c
index 0ecf8a453e01..bfc25811985f 100644
--- a/sound/drivers/pcsp/pcsp_input.c
+++ b/sound/drivers/pcsp/pcsp_input.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/input.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "pcsp.h"
#include "pcsp_input.h"
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 29ebaa4ec0fd..3689f5f6be64 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -10,8 +10,8 @@
#include <linux/gfp.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <sound/pcm.h>
-#include <asm/io.h>
#include "pcsp.h"
static bool nforce_wa;
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 13a34e3c6382..1927b89e1d1f 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/rawmidi.h>
#include <sound/initval.h>
@@ -44,8 +45,6 @@
#include <linux/serial_reg.h>
#include <linux/jiffies.h>
-#include <asm/io.h>
-
MODULE_DESCRIPTION("MIDI serial u16550");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{ALSA, MIDI serial u16550}}");
@@ -174,9 +173,8 @@ static inline void snd_uart16550_add_timer(struct snd_uart16550 *uart)
{
if (!uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
- uart->buffer_timer.expires = jiffies + (HZ+255)/256;
+ mod_timer(&uart->buffer_timer, jiffies + (HZ + 255) / 256);
uart->timer_running = 1;
- add_timer(&uart->buffer_timer);
}
}
@@ -830,9 +828,8 @@ static int snd_uart16550_create(struct snd_card *card,
uart->prev_in = 0;
uart->rstatus = 0;
memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);
- init_timer(&uart->buffer_timer);
- uart->buffer_timer.function = snd_uart16550_buffer_timer;
- uart->buffer_timer.data = (unsigned long)uart;
+ setup_timer(&uart->buffer_timer, snd_uart16550_buffer_timer,
+ (unsigned long)uart);
uart->timer_running = 0;
/* Register device */
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index fc05a37fd017..289f041706cd 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -27,11 +27,11 @@
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/asoundef.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <sound/vx_core.h>
#include "vx_cmd.h"
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 0d580186ef1a..5cc356db5351 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -33,7 +33,7 @@
*/
#define MAX_MIDI_RX_BLOCKS 8
-#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */
+#define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 microseconds */
/* isochronous header parameters */
#define ISO_DATA_LENGTH_SHIFT 16
@@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data);
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags)
{
- s->unit = fw_unit_get(unit);
+ s->unit = unit;
s->direction = dir;
s->flags = flags;
s->context = ERR_PTR(-1);
@@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s)
{
WARN_ON(amdtp_stream_running(s));
mutex_destroy(&s->mutex);
- fw_unit_put(s->unit);
}
EXPORT_SYMBOL(amdtp_stream_destroy);
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index fc19c99654aa..611b7dae7ee5 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -116,11 +116,22 @@ end:
return err;
}
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
static void
bebob_card_free(struct snd_card *card)
{
struct snd_bebob *bebob = card->private_data;
+ snd_bebob_stream_destroy_duplex(bebob);
+ fw_unit_put(bebob->unit);
+
+ kfree(bebob->maudio_special_quirk);
+
if (bebob->card_index >= 0) {
mutex_lock(&devices_mutex);
clear_bit(bebob->card_index, devices_used);
@@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit,
card->private_free = bebob_card_free;
bebob->card = card;
- bebob->unit = unit;
+ bebob->unit = fw_unit_get(unit);
bebob->spec = spec;
mutex_init(&bebob->mutex);
spin_lock_init(&bebob->lock);
@@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit)
if (bebob == NULL)
return;
- kfree(bebob->maudio_special_quirk);
+ /* Awake bus-reset waiters. */
+ if (!completion_done(&bebob->bus_reset))
+ complete_all(&bebob->bus_reset);
- snd_bebob_stream_destroy_duplex(bebob);
- snd_card_disconnect(bebob->card);
+ /* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(bebob->card);
}
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 0ebcabfdc7ce..98e4fc8121a1 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob)
static void
destroy_both_connections(struct snd_bebob *bebob)
{
- break_both_connections(bebob);
-
cmp_connection_destroy(&bebob->in_conn);
cmp_connection_destroy(&bebob->out_conn);
}
@@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob)
mutex_unlock(&bebob->mutex);
}
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob)
{
- mutex_lock(&bebob->mutex);
-
- amdtp_stream_pcm_abort(&bebob->rx_stream);
- amdtp_stream_pcm_abort(&bebob->tx_stream);
-
- amdtp_stream_stop(&bebob->rx_stream);
- amdtp_stream_stop(&bebob->tx_stream);
-
amdtp_stream_destroy(&bebob->rx_stream);
amdtp_stream_destroy(&bebob->tx_stream);
destroy_both_connections(bebob);
-
- mutex_unlock(&bebob->mutex);
}
/*
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index fa9cf761b610..07dbd01d7a6b 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -311,14 +311,21 @@ end:
return err;
}
+/*
+ * This function should be called before starting streams or after stopping
+ * streams.
+ */
static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
{
- amdtp_stream_destroy(stream);
+ struct fw_iso_resources *resources;
if (stream == &dice->tx_stream)
- fw_iso_resources_destroy(&dice->tx_resources);
+ resources = &dice->tx_resources;
else
- fw_iso_resources_destroy(&dice->rx_resources);
+ resources = &dice->rx_resources;
+
+ amdtp_stream_destroy(stream);
+ fw_iso_resources_destroy(resources);
}
int snd_dice_stream_init_duplex(struct snd_dice *dice)
@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
goto end;
err = init_stream(dice, &dice->rx_stream);
+ if (err < 0)
+ destroy_stream(dice, &dice->tx_stream);
end:
return err;
}
@@ -340,10 +349,7 @@ 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;
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 90d8f40ff727..70a111d7f428 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice)
strcpy(card->mixername, "DICE");
}
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
static void dice_card_free(struct snd_card *card)
{
struct snd_dice *dice = card->private_data;
+ snd_dice_stream_destroy_duplex(dice);
snd_dice_transaction_destroy(dice);
+ fw_unit_put(dice->unit);
+
mutex_destroy(&dice->mutex);
}
@@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
dice = card->private_data;
dice->card = card;
- dice->unit = unit;
+ dice->unit = fw_unit_get(unit);
card->private_free = dice_card_free;
spin_lock_init(&dice->lock);
@@ -305,10 +314,7 @@ 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);
-
+ /* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(dice->card);
}
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c
index 3e2ed8e82cbc..2682e7e3e5c9 100644
--- a/sound/firewire/fireworks/fireworks.c
+++ b/sound/firewire/fireworks/fireworks.c
@@ -173,11 +173,23 @@ end:
return err;
}
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
static void
efw_card_free(struct snd_card *card)
{
struct snd_efw *efw = card->private_data;
+ snd_efw_stream_destroy_duplex(efw);
+ snd_efw_transaction_remove_instance(efw);
+ fw_unit_put(efw->unit);
+
+ kfree(efw->resp_buf);
+
if (efw->card_index >= 0) {
mutex_lock(&devices_mutex);
clear_bit(efw->card_index, devices_used);
@@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card)
}
mutex_destroy(&efw->mutex);
- kfree(efw->resp_buf);
}
static int
@@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit,
card->private_free = efw_card_free;
efw->card = card;
- efw->unit = unit;
+ efw->unit = fw_unit_get(unit);
mutex_init(&efw->mutex);
spin_lock_init(&efw->lock);
init_waitqueue_head(&efw->hwdep_wait);
@@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit)
{
struct snd_efw *efw = dev_get_drvdata(&unit->device);
- snd_efw_stream_destroy_duplex(efw);
- snd_efw_transaction_remove_instance(efw);
-
- snd_card_disconnect(efw->card);
+ /* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(efw->card);
}
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index 4f440e163667..c55db1bddc80 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -100,17 +100,22 @@ end:
return err;
}
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
static void
destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
{
- stop_stream(efw, stream);
-
- amdtp_stream_destroy(stream);
+ struct cmp_connection *conn;
if (stream == &efw->tx_stream)
- cmp_connection_destroy(&efw->out_conn);
+ conn = &efw->out_conn;
else
- cmp_connection_destroy(&efw->in_conn);
+ conn = &efw->in_conn;
+
+ amdtp_stream_destroy(stream);
+ cmp_connection_destroy(&efw->out_conn);
}
static int
@@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw)
void snd_efw_stream_destroy_duplex(struct snd_efw *efw)
{
- mutex_lock(&efw->mutex);
-
destroy_stream(efw, &efw->rx_stream);
destroy_stream(efw, &efw->tx_stream);
-
- mutex_unlock(&efw->mutex);
}
void snd_efw_stream_lock_changed(struct snd_efw *efw)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index bda845afb470..29ccb3637164 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -337,6 +337,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
stop_stream(oxfw, stream);
}
+/*
+ * This function should be called before starting the stream or after stopping
+ * the streams.
+ */
void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
struct amdtp_stream *stream)
{
@@ -347,8 +351,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
else
conn = &oxfw->in_conn;
- stop_stream(oxfw, stream);
-
amdtp_stream_destroy(stream);
cmp_connection_destroy(conn);
}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index 60e5cad0531a..8c6ce019f437 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -104,11 +104,23 @@ end:
return err;
}
+/*
+ * This module releases the FireWire unit data after all ALSA character devices
+ * are released by applications. This is for releasing stream data or finishing
+ * transactions safely. Thus at returning from .remove(), this module still keep
+ * references for the unit.
+ */
static void oxfw_card_free(struct snd_card *card)
{
struct snd_oxfw *oxfw = card->private_data;
unsigned int i;
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+ fw_unit_put(oxfw->unit);
+
for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
kfree(oxfw->tx_stream_formats[i]);
kfree(oxfw->rx_stream_formats[i]);
@@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit,
oxfw = card->private_data;
oxfw->card = card;
mutex_init(&oxfw->mutex);
- oxfw->unit = unit;
+ oxfw->unit = fw_unit_get(unit);
oxfw->device_info = (const struct device_info *)id->driver_data;
spin_lock_init(&oxfw->lock);
init_waitqueue_head(&oxfw->hwdep_wait);
@@ -212,12 +224,7 @@ 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);
-
+ /* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(oxfw->card);
}
diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c
index 1a3a6fa27158..88844881cbff 100644
--- a/sound/i2c/other/ak4113.c
+++ b/sound/i2c/other/ak4113.c
@@ -56,8 +56,7 @@ static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg)
static void snd_ak4113_free(struct ak4113 *chip)
{
- chip->init = 1; /* don't schedule new work */
- mb();
+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
cancel_delayed_work_sync(&chip->work);
kfree(chip);
}
@@ -89,6 +88,8 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
chip->write = write;
chip->private_data = private_data;
INIT_DELAYED_WORK(&chip->work, ak4113_stats);
+ atomic_set(&chip->wq_processing, 0);
+ mutex_init(&chip->reinit_mutex);
for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++)
chip->regmap[reg] = pgm[reg];
@@ -139,13 +140,13 @@ static void ak4113_init_regs(struct ak4113 *chip)
void snd_ak4113_reinit(struct ak4113 *chip)
{
- chip->init = 1;
- mb();
- flush_delayed_work(&chip->work);
+ if (atomic_inc_return(&chip->wq_processing) == 1)
+ cancel_delayed_work_sync(&chip->work);
+ mutex_lock(&chip->reinit_mutex);
ak4113_init_regs(chip);
+ mutex_unlock(&chip->reinit_mutex);
/* bring up statistics / event queing */
- chip->init = 0;
- if (chip->kctls[0])
+ if (atomic_dec_and_test(&chip->wq_processing))
schedule_delayed_work(&chip->work, HZ / 10);
}
EXPORT_SYMBOL_GPL(snd_ak4113_reinit);
@@ -632,8 +633,25 @@ static void ak4113_stats(struct work_struct *work)
{
struct ak4113 *chip = container_of(work, struct ak4113, work.work);
- if (!chip->init)
+ if (atomic_inc_return(&chip->wq_processing) == 1)
snd_ak4113_check_rate_and_errors(chip, chip->check_flags);
- schedule_delayed_work(&chip->work, HZ / 10);
+ if (atomic_dec_and_test(&chip->wq_processing))
+ schedule_delayed_work(&chip->work, HZ / 10);
+}
+
+#ifdef CONFIG_PM
+void snd_ak4113_suspend(struct ak4113 *chip)
+{
+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
+ cancel_delayed_work_sync(&chip->work);
+}
+EXPORT_SYMBOL(snd_ak4113_suspend);
+
+void snd_ak4113_resume(struct ak4113 *chip)
+{
+ atomic_dec(&chip->wq_processing);
+ snd_ak4113_reinit(chip);
}
+EXPORT_SYMBOL(snd_ak4113_resume);
+#endif
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index c7f56339415d..5a4cf3fab4ae 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -66,8 +66,7 @@ static void reg_dump(struct ak4114 *ak4114)
static void snd_ak4114_free(struct ak4114 *chip)
{
- chip->init = 1; /* don't schedule new work */
- mb();
+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
cancel_delayed_work_sync(&chip->work);
kfree(chip);
}
@@ -100,6 +99,8 @@ int snd_ak4114_create(struct snd_card *card,
chip->write = write;
chip->private_data = private_data;
INIT_DELAYED_WORK(&chip->work, ak4114_stats);
+ atomic_set(&chip->wq_processing, 0);
+ mutex_init(&chip->reinit_mutex);
for (reg = 0; reg < 6; reg++)
chip->regmap[reg] = pgm[reg];
@@ -122,6 +123,7 @@ int snd_ak4114_create(struct snd_card *card,
snd_ak4114_free(chip);
return err < 0 ? err : -EIO;
}
+EXPORT_SYMBOL(snd_ak4114_create);
void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char mask, unsigned char val)
{
@@ -131,6 +133,7 @@ void snd_ak4114_reg_write(struct ak4114 *chip, unsigned char reg, unsigned char
reg_write(chip, reg,
(chip->txcsb[reg-AK4114_REG_TXCSB0] & ~mask) | val);
}
+EXPORT_SYMBOL(snd_ak4114_reg_write);
static void ak4114_init_regs(struct ak4114 *chip)
{
@@ -152,15 +155,16 @@ static void ak4114_init_regs(struct ak4114 *chip)
void snd_ak4114_reinit(struct ak4114 *chip)
{
- chip->init = 1;
- mb();
- flush_delayed_work(&chip->work);
+ if (atomic_inc_return(&chip->wq_processing) == 1)
+ cancel_delayed_work_sync(&chip->work);
+ mutex_lock(&chip->reinit_mutex);
ak4114_init_regs(chip);
+ mutex_unlock(&chip->reinit_mutex);
/* bring up statistics / event queing */
- chip->init = 0;
- if (chip->kctls[0])
+ if (atomic_dec_and_test(&chip->wq_processing))
schedule_delayed_work(&chip->work, HZ / 10);
}
+EXPORT_SYMBOL(snd_ak4114_reinit);
static unsigned int external_rate(unsigned char rcs1)
{
@@ -505,6 +509,7 @@ int snd_ak4114_build(struct ak4114 *ak4114,
schedule_delayed_work(&ak4114->work, HZ / 10);
return 0;
}
+EXPORT_SYMBOL(snd_ak4114_build);
/* notify kcontrols if any parameters are changed */
static void ak4114_notify(struct ak4114 *ak4114,
@@ -560,6 +565,7 @@ int snd_ak4114_external_rate(struct ak4114 *ak4114)
rcs1 = reg_read(ak4114, AK4114_REG_RCS1);
return external_rate(rcs1);
}
+EXPORT_SYMBOL(snd_ak4114_external_rate);
int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
{
@@ -607,20 +613,30 @@ int snd_ak4114_check_rate_and_errors(struct ak4114 *ak4114, unsigned int flags)
}
return res;
}
+EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors);
static void ak4114_stats(struct work_struct *work)
{
struct ak4114 *chip = container_of(work, struct ak4114, work.work);
- if (!chip->init)
+ if (atomic_inc_return(&chip->wq_processing) == 1)
snd_ak4114_check_rate_and_errors(chip, chip->check_flags);
+ if (atomic_dec_and_test(&chip->wq_processing))
+ schedule_delayed_work(&chip->work, HZ / 10);
+}
- schedule_delayed_work(&chip->work, HZ / 10);
+#ifdef CONFIG_PM
+void snd_ak4114_suspend(struct ak4114 *chip)
+{
+ atomic_inc(&chip->wq_processing); /* don't schedule new work */
+ cancel_delayed_work_sync(&chip->work);
}
+EXPORT_SYMBOL(snd_ak4114_suspend);
-EXPORT_SYMBOL(snd_ak4114_create);
-EXPORT_SYMBOL(snd_ak4114_reg_write);
-EXPORT_SYMBOL(snd_ak4114_reinit);
-EXPORT_SYMBOL(snd_ak4114_build);
-EXPORT_SYMBOL(snd_ak4114_external_rate);
-EXPORT_SYMBOL(snd_ak4114_check_rate_and_errors);
+void snd_ak4114_resume(struct ak4114 *chip)
+{
+ atomic_dec(&chip->wq_processing);
+ snd_ak4114_reinit(chip);
+}
+EXPORT_SYMBOL(snd_ak4114_resume);
+#endif
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
index 88452e899bd9..48848909a5a9 100644
--- a/sound/i2c/other/ak4117.c
+++ b/sound/i2c/other/ak4117.c
@@ -91,9 +91,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t
chip->read = read;
chip->write = write;
chip->private_data = private_data;
- init_timer(&chip->timer);
- chip->timer.data = (unsigned long)chip;
- chip->timer.function = snd_ak4117_timer;
+ setup_timer(&chip->timer, snd_ak4117_timer, (unsigned long)chip);
for (reg = 0; reg < 5; reg++)
chip->regmap[reg] = pgm[reg];
@@ -139,8 +137,7 @@ void snd_ak4117_reinit(struct ak4117 *chip)
/* release powerdown, everything is initialized now */
reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN);
chip->init = 0;
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
static unsigned int external_rate(unsigned char rcs1)
@@ -540,8 +537,7 @@ static void snd_ak4117_timer(unsigned long data)
if (chip->init)
return;
snd_ak4117_check_rate_and_errors(chip, 0);
- chip->timer.expires = 1 + jiffies;
- add_timer(&chip->timer);
+ mod_timer(&chip->timer, 1 + jiffies);
}
EXPORT_SYMBOL(snd_ak4117_create);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 67dbfde837ab..c65731088aa2 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -21,7 +21,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index f481a41e027e..769226515f0d 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -142,7 +142,6 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
struct snd_card *card;
struct snd_ad1816a *chip;
struct snd_opl3 *opl3;
- struct snd_timer *timer;
error = snd_card_new(&pcard->card->dev,
index[dev], id[dev], THIS_MODULE,
@@ -172,7 +171,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
- if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) {
+ if ((error = snd_ad1816a_pcm(chip, 0)) < 0) {
snd_card_free(card);
return error;
}
@@ -182,7 +181,7 @@ static int snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard,
return error;
}
- error = snd_ad1816a_timer(chip, 0, &timer);
+ error = snd_ad1816a_timer(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 01a07986f4a3..5c815f5fb044 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -22,11 +22,11 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/ioport.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/ad1816a.h>
-#include <asm/io.h>
#include <asm/dma.h>
static inline int snd_ad1816a_busy_wait(struct snd_ad1816a *chip)
@@ -675,7 +675,7 @@ static struct snd_pcm_ops snd_ad1816a_capture_ops = {
.pointer = snd_ad1816a_capture_pointer,
};
-int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
+int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device)
{
int error;
struct snd_pcm *pcm;
@@ -697,13 +697,10 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device, struct snd_pcm **rpcm)
64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
-int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
- struct snd_timer **rtimer)
+int snd_ad1816a_timer(struct snd_ad1816a *chip, int device)
{
struct snd_timer *timer;
struct snd_timer_id tid;
@@ -720,8 +717,6 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
timer->private_data = chip;
chip->timer = timer;
timer->hw = snd_ad1816a_timer_table;
- if (rtimer)
- *rtimer = timer;
return 0;
}
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 093f22a464d7..f159da4ec890 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -88,7 +88,6 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
{
struct snd_card *card;
struct snd_wss *chip;
- struct snd_pcm *pcm;
int error;
error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
@@ -103,7 +102,7 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
card->private_data = chip;
- error = snd_wss_pcm(chip, 0, &pcm);
+ error = snd_wss_pcm(chip, 0);
if (error < 0)
goto out;
@@ -112,10 +111,10 @@ static int snd_ad1848_probe(struct device *dev, unsigned int n)
goto out;
strcpy(card->driver, "AD1848");
- strcpy(card->shortname, pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[n], dma1[n]);
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
if (thinkpad[n])
strcat(card->longname, " [Thinkpad]");
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index 32d01525211d..bc9ea306ee02 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -233,7 +233,7 @@ static int snd_card_als100_probe(int dev,
irq[dev], dma8[dev], dma16[dev]);
}
- if ((error = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0) {
+ if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) {
snd_card_free(card);
return error;
}
diff --git a/sound/isa/azt2320.c b/sound/isa/azt2320.c
index 0ea75fc62072..fff186fa621e 100644
--- a/sound/isa/azt2320.c
+++ b/sound/isa/azt2320.c
@@ -29,7 +29,7 @@
activation method (full-duplex audio!).
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
@@ -215,7 +215,7 @@ static int snd_card_azt2320_probe(int dev,
sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
- error = snd_wss_pcm(chip, 0, NULL);
+ error = snd_wss_pcm(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
@@ -225,7 +225,7 @@ static int snd_card_azt2320_probe(int dev,
snd_card_free(card);
return error;
}
- error = snd_wss_timer(chip, 0, NULL);
+ error = snd_wss_timer(chip, 0);
if (error < 0) {
snd_card_free(card);
return error;
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index 4778852a1201..2c89d95da674 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -307,7 +307,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
if (err < 0)
goto error;
- err = snd_wss_pcm(cmi->wss, 0, NULL);
+ err = snd_wss_pcm(cmi->wss, 0);
if (err < 0)
goto error;
@@ -318,7 +318,7 @@ static int snd_cmi8328_probe(struct device *pdev, unsigned int ndev)
if (err < 0)
goto error;
- if (snd_wss_timer(cmi->wss, 0, NULL) < 0)
+ if (snd_wss_timer(cmi->wss, 0) < 0)
snd_printk(KERN_WARNING "error initializing WSS timer\n");
if (mpuport[ndev] == SNDRV_AUTO_PORT) {
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index 7dba07a4343a..282cd75d2235 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -92,7 +92,6 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
{
struct snd_card *card;
struct snd_wss *chip;
- struct snd_pcm *pcm;
int error;
error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card);
@@ -106,15 +105,15 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
card->private_data = chip;
- error = snd_wss_pcm(chip, 0, &pcm);
+ error = snd_wss_pcm(chip, 0);
if (error < 0)
goto out;
strcpy(card->driver, "CS4231");
- strcpy(card->shortname, pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
- pcm->name, chip->port, irq[n], dma1[n]);
+ chip->pcm->name, chip->port, irq[n], dma1[n]);
if (dma2[n] >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", dma2[n]);
@@ -122,7 +121,7 @@ static int snd_cs4231_probe(struct device *dev, unsigned int n)
if (error < 0)
goto out;
- error = snd_wss_timer(chip, 0, NULL);
+ error = snd_wss_timer(chip, 0);
if (error < 0)
goto out;
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 750f51c904fc..9d7582c90a95 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -382,7 +382,6 @@ static int snd_cs423x_card_new(struct device *pdev, int dev,
static int snd_cs423x_probe(struct snd_card *card, int dev)
{
struct snd_card_cs4236 *acard;
- struct snd_pcm *pcm;
struct snd_wss *chip;
struct snd_opl3 *opl3;
int err;
@@ -404,7 +403,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
acard->chip = chip;
if (chip->hardware & WSS_HW_CS4236B_MASK) {
- err = snd_cs4236_pcm(chip, 0, &pcm);
+ err = snd_cs4236_pcm(chip, 0);
if (err < 0)
return err;
@@ -412,7 +411,7 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
if (err < 0)
return err;
} else {
- err = snd_wss_pcm(chip, 0, &pcm);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
return err;
@@ -420,17 +419,17 @@ static int snd_cs423x_probe(struct snd_card *card, int dev)
if (err < 0)
return err;
}
- strcpy(card->driver, pcm->name);
- strcpy(card->shortname, pcm->name);
+ strcpy(card->driver, chip->pcm->name);
+ strcpy(card->shortname, chip->pcm->name);
sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i",
- pcm->name,
+ chip->pcm->name,
chip->port,
irq[dev],
dma1[dev]);
if (dma2[dev] >= 0)
sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
return err;
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index c5adca300632..2b7cc596f4c6 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -79,7 +79,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
@@ -376,17 +376,14 @@ int snd_cs4236_create(struct snd_card *card,
return 0;
}
-int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_cs4236_pcm(struct snd_wss *chip, int device)
{
- struct snd_pcm *pcm;
int err;
- err = snd_wss_pcm(chip, device, &pcm);
+ err = snd_wss_pcm(chip, device);
if (err < 0)
return err;
- pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
- if (rpcm)
- *rpcm = pcm;
+ chip->pcm->info_flags &= ~SNDRV_PCM_INFO_JOINT_DUPLEX;
return 0;
}
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 76001fe0579d..1901c2bb6c3b 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -138,10 +138,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
{
struct snd_es1688 *chip = card->private_data;
struct snd_opl3 *opl3;
- struct snd_pcm *pcm;
int error;
- error = snd_es1688_pcm(card, chip, 0, &pcm);
+ error = snd_es1688_pcm(card, chip, 0);
if (error < 0)
return error;
@@ -150,9 +149,9 @@ static int snd_es1688_probe(struct snd_card *card, unsigned int n)
return error;
strlcpy(card->driver, "ES1688", sizeof(card->driver));
- strlcpy(card->shortname, pcm->name, sizeof(card->shortname));
+ strlcpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
snprintf(card->longname, sizeof(card->longname),
- "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port,
+ "%s at 0x%lx, irq %i, dma %i", chip->pcm->name, chip->port,
chip->irq, chip->dma8);
if (fm_port[n] == SNDRV_AUTO_PORT)
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index b5450143407b..e2cf508841b1 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -25,11 +25,11 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/es1688.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/dma.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -728,8 +728,7 @@ static struct snd_pcm_ops snd_es1688_capture_ops = {
.pointer = snd_es1688_capture_pointer,
};
-int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
- int device, struct snd_pcm **rpcm)
+int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device)
{
struct snd_pcm *pcm;
int err;
@@ -749,9 +748,6 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 64*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index b481bb8c31bc..5094b62d8f77 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -84,8 +84,8 @@
#include <linux/isapnp.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -1687,16 +1687,13 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = {
.pointer = snd_es18xx_capture_pointer,
};
-static int snd_es18xx_pcm(struct snd_card *card, int device,
- struct snd_pcm **rpcm)
+static int snd_es18xx_pcm(struct snd_card *card, int device)
{
struct snd_es18xx *chip = card->private_data;
struct snd_pcm *pcm;
char str[16];
int err;
- if (rpcm)
- *rpcm = NULL;
sprintf(str, "ES%x", chip->version);
if (chip->caps & ES18XX_PCM2)
err = snd_pcm_new(card, str, device, 2, 1, &pcm);
@@ -1722,9 +1719,6 @@ static int snd_es18xx_pcm(struct snd_card *card, int device,
snd_dma_isa_data(),
64*1024,
chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -2154,7 +2148,7 @@ static int snd_audiodrive_probe(struct snd_card *card, int dev)
chip->port,
irq[dev], dma1[dev]);
- err = snd_es18xx_pcm(card, 0, NULL);
+ err = snd_es18xx_pcm(card, 0);
if (err < 0)
return err;
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index 1eb2b1ec0fd9..32278847884f 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -569,7 +569,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
if (err < 0)
goto error;
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
goto error;
@@ -577,7 +577,7 @@ static int snd_galaxy_probe(struct device *dev, unsigned int n)
if (err < 0)
goto error;
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
goto error;
diff --git a/sound/isa/gus/gus_instr.c b/sound/isa/gus/gus_instr.c
deleted file mode 100644
index 4dc9caf8ddcf..000000000000
--- a/sound/isa/gus/gus_instr.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Routines for Gravis UltraSound soundcards - Synthesizer
- * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
- *
- *
- * 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.
- *
- * 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
- *
- */
-
-#include <linux/time.h>
-#include <sound/core.h>
-#include <sound/gus.h>
-
-/*
- *
- */
-
-int snd_gus_iwffff_put_sample(void *private_data, struct iwffff_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (wave->format & IWFFFF_WAVE_ROM)
- return 0; /* it's probably ok - verify the address? */
- if (wave->format & IWFFFF_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_IWFFFF,
- NULL, wave->size,
- wave->format & IWFFFF_WAVE_16BIT, 1,
- wave->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data,
- block->ptr, wave->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- wave->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_iwffff_get_sample(void *private_data, struct iwffff_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, wave->address.memory, wave->size,
- wave->format & IWFFFF_WAVE_ROM ? 1 : 0);
-}
-
-int snd_gus_iwffff_remove_sample(void *private_data, struct iwffff_wave *wave,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- if (wave->format & IWFFFF_WAVE_ROM)
- return 0; /* it's probably ok - verify the address? */
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_gf1_put_sample(void *private_data, struct gf1_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (wave->format & GF1_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_GF1,
- NULL, wave->size,
- wave->format & GF1_WAVE_16BIT, 1,
- wave->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data,
- block->ptr, wave->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- wave->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_gf1_get_sample(void *private_data, struct gf1_wave *wave,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, wave->address.memory, wave->size, 0);
-}
-
-int snd_gus_gf1_remove_sample(void *private_data, struct gf1_wave *wave,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, wave->address.memory);
-}
-
-/*
- *
- */
-
-int snd_gus_simple_put_sample(void *private_data, struct simple_instrument *instr,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
- struct snd_gf1_mem_block *block;
- int err;
-
- if (instr->format & SIMPLE_WAVE_STEREO)
- return -EINVAL; /* not supported */
- block = snd_gf1_mem_alloc(&gus->gf1.mem_alloc,
- SNDRV_GF1_MEM_OWNER_WAVE_SIMPLE,
- NULL, instr->size,
- instr->format & SIMPLE_WAVE_16BIT, 1,
- instr->share_id);
- if (block == NULL)
- return -ENOMEM;
- err = snd_gus_dram_write(gus, data, block->ptr, instr->size);
- if (err < 0) {
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 0);
- snd_gf1_mem_xfree(&gus->gf1.mem_alloc, block);
- snd_gf1_mem_lock(&gus->gf1.mem_alloc, 1);
- return err;
- }
- instr->address.memory = block->ptr;
- return 0;
-}
-
-int snd_gus_simple_get_sample(void *private_data, struct simple_instrument *instr,
- char __user *data, long len, int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gus_dram_read(gus, data, instr->address.memory, instr->size, 0);
-}
-
-int snd_gus_simple_remove_sample(void *private_data, struct simple_instrument *instr,
- int atomic)
-{
- struct snd_gus_card *gus = private_data;
-
- return snd_gf1_mem_free(&gus->gf1.mem_alloc, instr->address.memory);
-}
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 2dcf45bf7293..25f6788ccef3 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -849,7 +849,7 @@ static struct snd_pcm_ops snd_gf1_pcm_capture_ops = {
.pointer = snd_gf1_pcm_capture_pointer,
};
-int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, struct snd_pcm ** rpcm)
+int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
{
struct snd_card *card;
struct snd_kcontrol *kctl;
@@ -857,8 +857,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s
struct snd_pcm_substream *substream;
int capture, err;
- if (rpcm)
- *rpcm = NULL;
card = gus->card;
capture = !gus->interwave && !gus->ess_flag && !gus->ace_flag ? 1 : 0;
err = snd_pcm_new(card,
@@ -903,8 +901,6 @@ int snd_gf1_pcm_new(struct snd_gus_card * gus, int pcm_dev, int control_index, s
return err;
kctl->id.index = control_index;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index 21cc42e4c4be..3992912743f5 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -241,13 +241,11 @@ static struct snd_rawmidi_ops snd_gf1_uart_input =
.trigger = snd_gf1_uart_input_trigger,
};
-int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmidi ** rrawmidi)
+int snd_gf1_rawmidi_new(struct snd_gus_card *gus, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(gus->card, "GF1", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, gus->interwave ? "AMD InterWave" : "GF1");
@@ -256,7 +254,5 @@ int snd_gf1_rawmidi_new(struct snd_gus_card * gus, int device, struct snd_rawmid
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = gus;
gus->midi_uart = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return err;
}
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 7ce29ffa1af9..f0019715d82e 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -181,12 +181,12 @@ static int snd_gusclassic_probe(struct device *dev, unsigned int n)
if (error < 0)
goto out;
- error = snd_gf1_pcm_new(gus, 0, 0, NULL);
+ error = snd_gf1_pcm_new(gus, 0, 0);
if (error < 0)
goto out;
if (!gus->ace_flag) {
- error = snd_gf1_rawmidi_new(gus, 0, NULL);
+ error = snd_gf1_rawmidi_new(gus, 0);
if (error < 0)
goto out;
}
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 28a16936a397..693d95f46804 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -284,7 +284,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
}
gus->codec_flag = 1;
- error = snd_es1688_pcm(card, es1688, 0, NULL);
+ error = snd_es1688_pcm(card, es1688, 0);
if (error < 0)
goto out;
@@ -295,7 +295,7 @@ static int snd_gusextreme_probe(struct device *dev, unsigned int n)
snd_component_add(card, "ES1688");
if (pcm_channels[n] > 0) {
- error = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ error = snd_gf1_pcm_new(gus, 1, 1);
if (error < 0)
goto out;
}
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index 39df36ca3acb..8216e8d8f017 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -309,7 +309,7 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (err < 0)
goto _err;
- err = snd_wss_pcm(wss, 0, NULL);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
goto _err;
@@ -317,19 +317,19 @@ static int snd_gusmax_probe(struct device *pdev, unsigned int dev)
if (err < 0)
goto _err;
- err = snd_wss_timer(wss, 2, NULL);
+ err = snd_wss_timer(wss, 2);
if (err < 0)
goto _err;
if (pcm_channels[dev] > 0) {
- if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+ if ((err = snd_gf1_pcm_new(gus, 1, 1)) < 0)
goto _err;
}
err = snd_gusmax_mixer(wss);
if (err < 0)
goto _err;
- err = snd_gf1_rawmidi_new(gus, 0, NULL);
+ err = snd_gf1_rawmidi_new(gus, 0);
if (err < 0)
goto _err;
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index ad55e5cb8e94..70d0040484c8 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -647,7 +647,6 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
#ifdef SNDRV_STB
struct snd_i2c_bus *i2c_bus;
#endif
- struct snd_pcm *pcm;
char *str;
int err;
@@ -695,14 +694,15 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
if (err < 0)
return err;
- err = snd_wss_pcm(wss, 0, &pcm);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
return err;
- sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A');
- strcat(pcm->name, " (codec)");
+ sprintf(wss->pcm->name + strlen(wss->pcm->name), " rev %c",
+ gus->revision + 'A');
+ strcat(wss->pcm->name, " (codec)");
- err = snd_wss_timer(wss, 2, NULL);
+ err = snd_wss_timer(wss, 2);
if (err < 0)
return err;
@@ -711,7 +711,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
return err;
if (pcm_channels[dev] > 0) {
- err = snd_gf1_pcm_new(gus, 1, 1, NULL);
+ err = snd_gf1_pcm_new(gus, 1, 1);
if (err < 0)
return err;
}
@@ -740,7 +740,7 @@ static int snd_interwave_probe(struct snd_card *card, int dev)
#endif
gus->uart_enable = midi[dev];
- if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0)
+ if ((err = snd_gf1_rawmidi_new(gus, 0)) < 0)
return err;
#ifndef SNDRV_STB
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
index 1cee18fb28a8..835d4aa26761 100644
--- a/sound/isa/msnd/msnd.c
+++ b/sound/isa/msnd/msnd.c
@@ -679,8 +679,7 @@ static struct snd_pcm_ops snd_msnd_capture_ops = {
};
-int snd_msnd_pcm(struct snd_card *card, int device,
- struct snd_pcm **rpcm)
+int snd_msnd_pcm(struct snd_card *card, int device)
{
struct snd_msnd *chip = card->private_data;
struct snd_pcm *pcm;
@@ -696,9 +695,6 @@ int snd_msnd_pcm(struct snd_card *card, int device,
pcm->private_data = chip;
strcpy(pcm->name, "Hurricane");
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
EXPORT_SYMBOL(snd_msnd_pcm);
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
index dbac3a42347b..5f3c7dcd9f9d 100644
--- a/sound/isa/msnd/msnd.h
+++ b/sound/isa/msnd/msnd.h
@@ -297,7 +297,7 @@ int snd_msnd_disable_irq(struct snd_msnd *chip);
void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
int snd_msnd_DARQ(struct snd_msnd *chip, int start);
-int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
+int snd_msnd_pcm(struct snd_card *card, int device);
int snd_msndmidi_new(struct snd_card *card, int device);
void snd_msndmidi_input_read(void *mpu);
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 5016bf957f51..4c072666115d 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -582,7 +582,7 @@ static int snd_msnd_attach(struct snd_card *card)
if (err < 0)
goto err_release_region;
- err = snd_msnd_pcm(card, 0, NULL);
+ err = snd_msnd_pcm(card, 0);
if (err < 0) {
printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
goto err_release_region;
@@ -627,8 +627,7 @@ static int snd_msnd_attach(struct snd_card *card)
return 0;
err_release_region:
- if (chip->mappedbase)
- iounmap(chip->mappedbase);
+ iounmap(chip->mappedbase);
release_mem_region(chip->base, BUFFSIZE);
release_region(chip->io, DSP_NUMIO);
free_irq(chip->irq, chip);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index a219bc37816b..ae133633a420 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -26,6 +26,7 @@
#include <linux/pm.h>
#include <linux/pnp.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/wss.h>
#include <sound/mpu401.h>
@@ -33,8 +34,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Yamaha OPL3SA2+");
MODULE_LICENSE("GPL");
@@ -684,7 +683,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
return err;
}
chip->wss = wss;
- err = snd_wss_pcm(wss, 0, NULL);
+ err = snd_wss_pcm(wss, 0);
if (err < 0)
return err;
err = snd_wss_mixer(wss);
@@ -693,7 +692,7 @@ static int snd_opl3sa2_probe(struct snd_card *card, int dev)
err = snd_opl3sa2_mixer(card);
if (err < 0)
return err;
- err = snd_wss_timer(wss, 0, NULL);
+ err = snd_wss_timer(wss, 0);
if (err < 0)
return err;
if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) {
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index c2ca681ac51b..3a9067db1a84 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -29,7 +29,7 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/wss.h>
@@ -1270,8 +1270,6 @@ static int snd_miro_probe(struct snd_card *card)
int error;
struct snd_miro *miro = card->private_data;
struct snd_wss *codec;
- struct snd_timer *timer;
- struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
if (!miro->res_mc_base) {
@@ -1310,7 +1308,7 @@ static int snd_miro_probe(struct snd_card *card)
if (error < 0)
return error;
- error = snd_wss_pcm(codec, 0, &pcm);
+ error = snd_wss_pcm(codec, 0);
if (error < 0)
return error;
@@ -1318,11 +1316,11 @@ static int snd_miro_probe(struct snd_card *card)
if (error < 0)
return error;
- error = snd_wss_timer(codec, 0, &timer);
+ error = snd_wss_timer(codec, 0);
if (error < 0)
return error;
- miro->pcm = pcm;
+ miro->pcm = codec->pcm;
error = snd_miro_mixer(card, miro);
if (error < 0)
@@ -1356,8 +1354,8 @@ static int snd_miro_probe(struct snd_card *card)
strcpy(card->driver, "miro");
sprintf(card->longname, "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, miro->name, pcm->name, miro->wss_base + 4,
- miro->irq, miro->dma1, miro->dma2);
+ card->shortname, miro->name, codec->pcm->name,
+ miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
rmidi = NULL;
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index c9b582848603..0a5266003786 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -29,7 +29,7 @@
#include <linux/delay.h>
#include <linux/pnp.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/tlv.h>
@@ -820,10 +820,6 @@ static int snd_opti9xx_probe(struct snd_card *card)
int xdma2;
struct snd_opti9xx *chip = card->private_data;
struct snd_wss *codec;
-#ifdef CS4231
- struct snd_timer *timer;
-#endif
- struct snd_pcm *pcm;
struct snd_rawmidi *rmidi;
struct snd_hwdep *synth;
@@ -855,7 +851,7 @@ static int snd_opti9xx_probe(struct snd_card *card)
if (error < 0)
return error;
chip->codec = codec;
- error = snd_wss_pcm(codec, 0, &pcm);
+ error = snd_wss_pcm(codec, 0);
if (error < 0)
return error;
error = snd_wss_mixer(codec);
@@ -867,7 +863,7 @@ static int snd_opti9xx_probe(struct snd_card *card)
return error;
#endif
#ifdef CS4231
- error = snd_wss_timer(codec, 0, &timer);
+ error = snd_wss_timer(codec, 0);
if (error < 0)
return error;
#endif
@@ -884,11 +880,12 @@ static int snd_opti9xx_probe(struct snd_card *card)
sprintf(card->shortname, "OPTi %s", card->driver);
#if defined(CS4231) || defined(OPTi93X)
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
- card->shortname, pcm->name,
+ card->shortname, codec->pcm->name,
chip->wss_base + 4, irq, dma1, xdma2);
#else
sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
- card->shortname, pcm->name, chip->wss_base + 4, irq, dma1);
+ card->shortname, codec->pcm->name, chip->wss_base + 4, irq,
+ dma1);
#endif /* CS4231 || OPTi93X */
if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 45fcdff611f9..94c411299e5a 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -26,11 +26,11 @@
#include <linux/ioport.h>
#include <linux/export.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/emu8000.h>
#include <sound/emu8000_reg.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/init.h>
#include <sound/control.h>
#include <sound/initval.h>
@@ -378,13 +378,12 @@ init_arrays(struct snd_emu8000 *emu)
static void
size_dram(struct snd_emu8000 *emu)
{
- int i, size, detected_size;
+ int i, size;
if (emu->dram_checked)
return;
size = 0;
- detected_size = 0;
/* write out a magic number */
snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
@@ -392,10 +391,19 @@ size_dram(struct snd_emu8000 *emu)
EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
+ snd_emu8000_write_wait(emu);
- while (size < EMU8000_MAX_DRAM) {
+ /*
+ * Detect first 512 KiB. If a write succeeds at the beginning of a
+ * 512 KiB page we assume that the whole page is there.
+ */
+ EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
+ EMU8000_SMLD_READ(emu); /* discard stale data */
+ if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
+ goto skip_detect; /* No RAM */
+ snd_emu8000_read_wait(emu);
- size += 512 * 1024; /* increment 512kbytes */
+ for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
/* Write a unique data on the test address.
* if the address is out of range, the data is written on
@@ -431,18 +439,9 @@ size_dram(struct snd_emu8000 *emu)
snd_emu8000_read_wait(emu);
/* Otherwise, it's valid memory. */
- detected_size = size + 512 * 1024;
- }
-
- /* Distinguish 512 KiB from 0. */
- if (detected_size == 0) {
- snd_emu8000_read_wait(emu);
- EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
- EMU8000_SMLD_READ(emu); /* discard stale data */
- if (EMU8000_SMLD_READ(emu) == UNIQUE_ID1)
- detected_size = 512 * 1024;
}
+skip_detect:
/* wait until FULL bit in SMAxW register is false */
for (i = 0; i < 10000; i++) {
if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
@@ -454,10 +453,10 @@ size_dram(struct snd_emu8000 *emu)
snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
- snd_printdd("EMU8000 [0x%lx]: %d Kb on-board memory detected\n",
- emu->port1, detected_size/1024);
+ pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
+ emu->port1, size/1024);
- emu->mem_size = detected_size;
+ emu->mem_size = size;
emu->dram_checked = 1;
}
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index c99c6078be33..71d13c0bb746 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -20,7 +20,7 @@
*/
#include "emu8000_local.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/moduleparam.h>
static int emu8000_reset_addr;
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index 2f85c66f8e38..250fd0006b53 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -207,8 +207,7 @@ static void emu8k_pcm_timer_func(unsigned long data)
rec->last_ptr = ptr;
/* reprogram timer */
- rec->timer.expires = jiffies + 1;
- add_timer(&rec->timer);
+ mod_timer(&rec->timer, jiffies + 1);
/* update period */
if (rec->period_pos >= (int)rec->period_size) {
@@ -240,9 +239,7 @@ static int emu8k_pcm_open(struct snd_pcm_substream *subs)
runtime->private_data = rec;
spin_lock_init(&rec->timer_lock);
- init_timer(&rec->timer);
- rec->timer.function = emu8k_pcm_timer_func;
- rec->timer.data = (unsigned long)rec;
+ setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec);
runtime->hw = emu8k_pcm_hw;
runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
@@ -359,8 +356,7 @@ static void start_voice(struct snd_emu8k_pcm *rec, int ch)
/* start timer */
spin_lock_irqsave(&rec->timer_lock, flags);
if (! rec->timer_running) {
- rec->timer.expires = jiffies + 1;
- add_timer(&rec->timer);
+ mod_timer(&rec->timer, jiffies + 1);
rec->timer_running = 1;
}
spin_unlock_irqrestore(&rec->timer_lock, flags);
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 95b39beb61c1..72332dfada9a 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -103,8 +103,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
hw = dev->driver_data;
if (hw->pcm)
snd_device_free(dev->card, hw->pcm);
- if (hw->emu)
- snd_emux_free(hw->emu);
+ snd_emux_free(hw->emu);
snd_util_memhdr_free(hw->memhdr);
hw->emu = NULL;
hw->memhdr = NULL;
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c
index 90d2eba549e9..6b4884d052a5 100644
--- a/sound/isa/sb/jazz16.c
+++ b/sound/isa/sb/jazz16.c
@@ -297,7 +297,7 @@ static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
port[dev], xirq, xdma8, xdma16);
- err = snd_sb8dsp_pcm(chip, 0, NULL);
+ err = snd_sb8dsp_pcm(chip, 0);
if (err < 0)
goto err_free;
err = snd_sbmixer_new(chip);
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 3f694543a7ea..4a7d7c89808f 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -374,7 +374,7 @@ static int snd_sb16_probe(struct snd_card *card, int dev)
if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0)
return err;
- if ((err = snd_sb16dsp_pcm(chip, 0, &chip->pcm)) < 0)
+ if ((err = snd_sb16dsp_pcm(chip, 0)) < 0)
return err;
strcpy(card->driver,
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 72b10f4f3e70..8b2d6c6bfe97 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -33,7 +33,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
@@ -860,19 +860,18 @@ static struct snd_pcm_ops snd_sb16_capture_ops = {
.pointer = snd_sb16_capture_pointer,
};
-int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm)
+int snd_sb16dsp_pcm(struct snd_sb *chip, int device)
{
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0)
return err;
sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
pcm->private_data = chip;
+ chip->pcm = pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops);
@@ -885,9 +884,6 @@ int snd_sb16dsp_pcm(struct snd_sb * chip, int device, struct snd_pcm ** rpcm)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_isa_data(),
64*1024, 128*1024);
-
- if (rpcm)
- *rpcm = pcm;
return 0;
}
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 6c32b3aa34af..b8e2391c33ff 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -157,7 +157,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
goto _err;
}
- if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0)
+ if ((err = snd_sb8dsp_pcm(chip, 0)) < 0)
goto _err;
if ((err = snd_sbmixer_new(chip)) < 0)
@@ -182,7 +182,7 @@ static int snd_sb8_probe(struct device *pdev, unsigned int dev)
goto _err;
}
- if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0)
+ if ((err = snd_sb8dsp_midi(chip, 0)) < 0)
goto _err;
strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index 24d4121ab0e0..9043397fe62f 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -30,7 +30,7 @@
* Cleaned up and rewrote lowlevel routines.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/init.h>
#include <linux/time.h>
@@ -594,15 +594,13 @@ static struct snd_pcm_ops snd_sb8_capture_ops = {
.pointer = snd_sb8_capture_pointer,
};
-int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
+int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
{
struct snd_card *card = chip->card;
struct snd_pcm *pcm;
int err;
size_t max_prealloc = 64 * 1024;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
return err;
sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
@@ -618,8 +616,6 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm)
snd_dma_isa_data(),
64*1024, max_prealloc);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index 988a8b73475f..d551c50e549f 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -26,7 +26,7 @@
* Added full duplex UART mode for DSP version 2.0 and later.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/sb.h>
@@ -216,8 +216,7 @@ static void snd_sb8dsp_midi_output_timer(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&chip->open_lock, flags);
- chip->midi_timer.expires = 1 + jiffies;
- add_timer(&chip->midi_timer);
+ mod_timer(&chip->midi_timer, 1 + jiffies);
spin_unlock_irqrestore(&chip->open_lock, flags);
snd_sb8dsp_midi_output_write(substream);
}
@@ -231,11 +230,10 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
spin_lock_irqsave(&chip->open_lock, flags);
if (up) {
if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) {
- init_timer(&chip->midi_timer);
- chip->midi_timer.function = snd_sb8dsp_midi_output_timer;
- chip->midi_timer.data = (unsigned long) substream;
- chip->midi_timer.expires = 1 + jiffies;
- add_timer(&chip->midi_timer);
+ setup_timer(&chip->midi_timer,
+ snd_sb8dsp_midi_output_timer,
+ (unsigned long) substream);
+ mod_timer(&chip->midi_timer, 1 + jiffies);
chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER;
}
} else {
@@ -263,13 +261,11 @@ static struct snd_rawmidi_ops snd_sb8dsp_midi_input =
.trigger = snd_sb8dsp_midi_input_trigger,
};
-int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawmidi)
+int snd_sb8dsp_midi(struct snd_sb *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "SB8 MIDI", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "SB8 MIDI");
@@ -280,7 +276,5 @@ int snd_sb8dsp_midi(struct snd_sb *chip, int device, struct snd_rawmidi ** rrawm
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index f22b4480828e..787a4ade4afd 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -26,11 +26,11 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/sb.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/dma.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index e403334a19ad..add1d3f99609 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -19,7 +19,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <sound/core.h>
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 15a152eaa2e8..51cfa7615f72 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -625,7 +625,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev)
if (err < 0)
goto err_unmap2;
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR PFX
"error creating new WSS PCM device\n");
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 44405df7d4be..7b248cdf06e2 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/isa.h>
#include <linux/delay.h>
#include <linux/firmware.h>
@@ -877,7 +878,6 @@ static int create_ad1845(struct snd_card *card, unsigned port,
codec_type, WSS_HWSHARE_DMA1, &chip);
if (!err) {
unsigned long flags;
- struct snd_pcm *pcm;
if (sscape->type != SSCAPE_VIVO) {
/*
@@ -893,7 +893,7 @@ static int create_ad1845(struct snd_card *card, unsigned port,
}
- err = snd_wss_pcm(chip, 0, &pcm);
+ err = snd_wss_pcm(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No PCM device "
"for AD1845 chip\n");
@@ -907,7 +907,7 @@ static int create_ad1845(struct snd_card *card, unsigned port,
goto _error;
}
if (chip->hardware != WSS_HW_AD1848) {
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No timer device "
"for AD1845 chip\n");
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index bfbf38cf9841..a0987a57c8a9 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -380,11 +380,11 @@ snd_wavefront_probe (struct snd_card *card, int dev)
return err;
}
- err = snd_wss_pcm(chip, 0, NULL);
+ err = snd_wss_pcm(chip, 0);
if (err < 0)
return err;
- err = snd_wss_timer(chip, 0, NULL);
+ err = snd_wss_timer(chip, 0);
if (err < 0)
return err;
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index b77883c7ee76..b5a19708473a 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 7dc991682297..8a80fc6a616b 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -47,7 +47,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/wait.h>
@@ -356,8 +356,7 @@ static void snd_wavefront_midi_output_timer(unsigned long data)
unsigned long flags;
spin_lock_irqsave (&midi->virtual, flags);
- midi->timer.expires = 1 + jiffies;
- add_timer(&midi->timer);
+ mod_timer(&midi->timer, 1 + jiffies);
spin_unlock_irqrestore (&midi->virtual, flags);
snd_wavefront_midi_output_write(card);
}
@@ -384,11 +383,10 @@ static void snd_wavefront_midi_output_trigger(struct snd_rawmidi_substream *subs
if (up) {
if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) {
if (!midi->istimer) {
- init_timer(&midi->timer);
- midi->timer.function = snd_wavefront_midi_output_timer;
- midi->timer.data = (unsigned long) substream->rmidi->card->private_data;
- midi->timer.expires = 1 + jiffies;
- add_timer(&midi->timer);
+ setup_timer(&midi->timer,
+ snd_wavefront_midi_output_timer,
+ (unsigned long) substream->rmidi->card->private_data);
+ mod_timer(&midi->timer, 1 + jiffies);
}
midi->istimer++;
midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER;
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index e5db001363ee..33f5ec14fcfa 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -20,7 +20,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 347bb1bda110..913b731d2236 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -31,12 +31,12 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/wss.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
@@ -1923,7 +1923,7 @@ static struct snd_pcm_ops snd_wss_capture_ops = {
.pointer = snd_wss_capture_pointer,
};
-int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
+int snd_wss_pcm(struct snd_wss *chip, int device)
{
struct snd_pcm *pcm;
int err;
@@ -1949,8 +1949,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm)
64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
chip->pcm = pcm;
- if (rpcm)
- *rpcm = pcm;
return 0;
}
EXPORT_SYMBOL(snd_wss_pcm);
@@ -1961,7 +1959,7 @@ static void snd_wss_timer_free(struct snd_timer *timer)
chip->timer = NULL;
}
-int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
+int snd_wss_timer(struct snd_wss *chip, int device)
{
struct snd_timer *timer;
struct snd_timer_id tid;
@@ -1980,8 +1978,6 @@ int snd_wss_timer(struct snd_wss *chip, int device, struct snd_timer **rtimer)
timer->private_free = snd_wss_timer_free;
timer->hw = snd_wss_timer_table;
chip->timer = timer;
- if (rtimer)
- *rtimer = timer;
return 0;
}
EXPORT_SYMBOL(snd_wss_timer);
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 13c214466d3b..1c56bf58eff9 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -851,7 +851,7 @@ static int __init AtaIrqInit(void)
st_mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
st_mfp.tim_ct_a = 8; /* Turn on event counting. */
/* Register interrupt handler. */
- if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
+ if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, 0, "DMA sound",
AtaInterrupt))
return 0;
st_mfp.int_en_a |= 0x20; /* Turn interrupt on. */
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index c23f9f95bfa5..a8ceef8d1a8d 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -675,7 +675,7 @@ static void dsp_write_flush(void)
timeout);
clear_bit(F_WRITEFLUSH, &dev.flags);
if (!signal_pending(current)) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE));
}
clear_bit(F_WRITING, &dev.flags);
@@ -1288,7 +1288,7 @@ static int __init calibrate_adc(WORD srate)
& ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags);
if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 3);
return 0;
}
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index ca0d6e9f49f5..81314f9e2ccb 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -1228,7 +1228,7 @@ static void __exit cleanup_pss(void)
{
if(!pss_no_sound)
{
- if(fw_load && pss_synth)
+ if (fw_load)
vfree(pss_synth);
if(pssmss)
unload_pss_mss(&cfg2);
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index a33e8ce8085b..213a416b6e0b 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -1654,7 +1654,7 @@ static int drain_dac(struct cs4297a_state *s, int nonblock)
s->dma_dac.hwptr = s->dma_dac.swptr = hwptr;
spin_unlock_irqrestore(&s->lock, flags);
remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
return 0;
}
diff --git a/sound/oss/trix.c b/sound/oss/trix.c
index 944e0c015485..3c494dc93b93 100644
--- a/sound/oss/trix.c
+++ b/sound/oss/trix.c
@@ -487,7 +487,7 @@ static int __init init_trix(void)
static void __exit cleanup_trix(void)
{
- if (fw_load && trix_boot)
+ if (fw_load)
vfree(trix_boot);
if (sb)
unload_trix_sb(&cfg2);
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 29604a239c44..99b64cb3cef8 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -44,6 +44,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -52,7 +53,6 @@
#include <sound/initval.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/parisc-device.h>
@@ -893,9 +893,7 @@ snd_harmony_free(struct snd_harmony *h)
if (h->irq >= 0)
free_irq(h->irq, h);
- if (h->iobase)
- iounmap(h->iobase);
-
+ iounmap(h->iobase);
kfree(h);
return 0;
}
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 50dd0086cfb1..edfc1b8d553e 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -793,6 +793,15 @@ config SND_RME9652
To compile this driver as a module, choose M here: the module
will be called snd-rme9652.
+config SND_SE6X
+ tristate "Studio Evolution SE6X"
+ depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict
+ select SND_OXYGEN_LIB
+ select SND_PCM
+ select SND_MPU401_UART
+ help
+ Say Y or M here only if you actually have this sound card.
+
config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
depends on X86_32
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 1610c38337af..850a8c984c25 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -40,14 +40,13 @@
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/ac97_codec.h>
-#include <asm/io.h>
-
#include "ad1889.h"
#include "ac97/ac97_id.h"
@@ -623,14 +622,11 @@ snd_ad1889_interrupt(int irq, void *dev_id)
}
static int
-snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
+snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device)
{
int err;
struct snd_pcm *pcm;
- if (rpcm)
- *rpcm = NULL;
-
err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -658,9 +654,6 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm)
return err;
}
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
@@ -859,12 +852,9 @@ snd_ad1889_free(struct snd_ad1889 *chip)
free_irq(chip->irq, chip);
skip_hw:
- if (chip->iobase)
- iounmap(chip->iobase);
-
+ iounmap(chip->iobase);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
-
kfree(chip);
return 0;
}
@@ -1016,7 +1006,7 @@ snd_ad1889_probe(struct pci_dev *pci,
if (err < 0)
goto free_and_ret;
- err = snd_ad1889_pcm_init(chip, 0, NULL);
+ err = snd_ad1889_pcm_init(chip, 0);
if (err < 0)
goto free_and_ret;
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index af89e42b2160..c8d499575c01 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -25,7 +25,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1873,7 +1873,6 @@ static int snd_ali_mixer(struct snd_ali *codec)
#ifdef CONFIG_PM_SLEEP
static int ali_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
struct snd_ali_image *im;
@@ -1914,16 +1913,11 @@ static int ali_suspend(struct device *dev)
outl(0xffffffff, ALI_REG(chip, ALI_STOP));
spin_unlock_irq(&chip->reg_lock);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int ali_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ali *chip = card->private_data;
struct snd_ali_image *im;
@@ -1933,15 +1927,6 @@ static int ali_resume(struct device *dev)
if (!im)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
spin_lock_irq(&chip->reg_lock);
for (i = 0; i < ALI_CHANNELS; i++) {
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 7bb6ac565107..57e034f208dc 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -37,8 +37,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -728,35 +727,20 @@ static int snd_als300_create(struct snd_card *card,
#ifdef CONFIG_PM_SLEEP
static int snd_als300_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_als300 *chip = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_als300_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_als300 *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_als300_init(chip);
snd_ac97_resume(chip->ac97);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index d3e6424ee656..a3dea464134d 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -65,7 +65,7 @@
* - power management? (card can do voice wakeup according to datasheet!!)
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/gameport.h>
@@ -988,7 +988,6 @@ static void snd_card_als4000_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_als4000_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_card_als4000 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
@@ -997,29 +996,15 @@ static int snd_als4000_suspend(struct device *dev)
snd_pcm_suspend_all(chip->pcm);
snd_sbmixer_suspend(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_als4000_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_card_als4000 *acard = card->private_data;
struct snd_sb *chip = acard->chip;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_als4000_configure(chip);
snd_sbdsp_reset(chip);
snd_sbmixer_resume(chip);
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index e9273fb2a505..e5cd7be85355 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -540,9 +540,8 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
expiry = HZ / 200;
expiry = max(expiry, 1); /* don't let it be zero! */
- dpcm->timer.expires = jiffies + expiry;
+ mod_timer(&dpcm->timer, jiffies + expiry);
dpcm->respawn_timer = 1;
- add_timer(&dpcm->timer);
}
static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
@@ -1064,9 +1063,8 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
If internal and other stream playing, can't switch
*/
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = snd_card_asihpi_timer_function;
+ setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+ (unsigned long) dpcm);
dpcm->substream = substream;
runtime->private_data = dpcm;
runtime->private_free = snd_card_asihpi_runtime_free;
@@ -1246,9 +1244,8 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
if (err)
return -EIO;
- init_timer(&dpcm->timer);
- dpcm->timer.data = (unsigned long) dpcm;
- dpcm->timer.function = snd_card_asihpi_timer_function;
+ setup_timer(&dpcm->timer, snd_card_asihpi_timer_function,
+ (unsigned long) dpcm);
dpcm->substream = substream;
runtime->private_data = dpcm;
runtime->private_free = snd_card_asihpi_runtime_free;
@@ -2832,14 +2829,11 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file,
/* results in /dev/snd/hwC#D0 file for each card with index #
also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card'
*/
-static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
- int device, struct snd_hwdep **rhwdep)
+static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, int device)
{
struct snd_hwdep *hw;
int err;
- if (rhwdep)
- *rhwdep = NULL;
err = snd_hwdep_new(asihpi->card, "HPI", device, &hw);
if (err < 0)
return err;
@@ -2849,8 +2843,6 @@ static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi,
hw->ops.ioctl = snd_asihpi_hpi_ioctl;
hw->ops.release = snd_asihpi_hpi_release;
hw->private_data = asihpi;
- if (rhwdep)
- *rhwdep = hw;
return 0;
}
@@ -2993,7 +2985,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
/* always create, can be enabled or disabled dynamically
by enable_hwdep module param*/
- snd_asihpi_hpi_new(asihpi, 0, NULL);
+ snd_asihpi_hpi_new(asihpi, 0);
strcpy(card->driver, "ASIHPI");
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index 2414d7a2239d..2d6364825d4d 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -47,7 +47,7 @@
/* operational/messaging errors */
#define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 901
-
+#define HPI6000_ERROR_RESP_GET_LEN 902
#define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 903
#define HPI6000_ERROR_MSG_GET_ADR 904
#define HPI6000_ERROR_RESP_GET_ADR 905
@@ -1365,7 +1365,10 @@ static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,
length = hpi_read_word(pdo, HPI_HIF_ADDR(length));
} while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);
if (!timeout)
- length = sizeof(struct hpi_response);
+ return HPI6000_ERROR_RESP_GET_LEN;
+
+ if (length > phr->size)
+ return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;
/* get the response */
p_data = (u32 *)phr;
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 6aa677e60555..6610bd096fc9 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -28,7 +28,7 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/pci.h>
#include <linux/stringify.h>
#include <linux/module.h>
@@ -153,6 +153,8 @@ long asihpi_hpi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto out;
}
+ res_max_size = min_t(size_t, res_max_size, sizeof(*hr));
+
switch (hm->h.function) {
case HPI_SUBSYS_CREATE_ADAPTER:
case HPI_ADAPTER_DELETE:
@@ -539,10 +541,8 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
/* unmap PCI memory space, mapped during device init. */
- for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; idx++) {
- if (pci.ap_mem_base[idx])
- iounmap(pci.ap_mem_base[idx]);
- }
+ for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
+ iounmap(pci.ap_mem_base[idx]);
if (pa->irq)
free_irq(pa->irq, pa);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 9c1c4452a8ee..d5f15c9bbeda 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -19,7 +19,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1474,7 +1474,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock,
*/
static int snd_atiixp_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp *chip = card->private_data;
int i;
@@ -1492,29 +1491,15 @@ static int snd_atiixp_suspend(struct device *dev)
snd_ac97_suspend(chip->ac97[i]);
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_atiixp_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_atiixp_aclink_reset(chip);
snd_atiixp_chip_start(chip);
@@ -1585,8 +1570,7 @@ static int snd_atiixp_free(struct atiixp *chip)
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index b2f63e0727de..0a38e08164ab 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -19,7 +19,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1120,7 +1120,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
*/
static int snd_atiixp_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp_modem *chip = card->private_data;
int i;
@@ -1132,29 +1131,15 @@ static int snd_atiixp_suspend(struct device *dev)
snd_ac97_suspend(chip->ac97[i]);
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_atiixp_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct atiixp_modem *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_atiixp_aclink_reset(chip);
snd_atiixp_chip_start(chip);
@@ -1211,8 +1196,7 @@ static int snd_atiixp_free(struct atiixp_modem *chip)
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 3a8fefefea77..bcc648bf6478 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -17,9 +17,8 @@
#ifndef __SOUND_AU88X0_H
#define __SOUND_AU88X0_H
-#ifdef __KERNEL__
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/rawmidi.h>
@@ -27,7 +26,6 @@
#include <sound/hwdep.h>
#include <sound/ac97_codec.h>
#include <sound/tlv.h>
-#endif
#ifndef CHIP_AU8820
#include "au88x0_eq.h"
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index e1cf01949fda..8d2fee7b33bd 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -229,9 +229,7 @@ static int snd_aw2_dev_free(struct snd_device *device)
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
/* release the i/o ports & memory */
- if (chip->iobase_virt)
- iounmap(chip->iobase_virt);
-
+ iounmap(chip->iobase_virt);
pci_release_regions(chip->pci);
/* disable the PCI entry */
pci_disable_device(chip->pci);
diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c
index 6d24e9536777..1d7890459334 100644
--- a/sound/pci/aw2/aw2-saa7146.c
+++ b/sound/pci/aw2/aw2-saa7146.c
@@ -27,7 +27,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index fdbb9c05c77b..a40a2b4c8fd7 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -179,7 +179,7 @@
* - use MMIO (memory-mapped I/O)? Slightly faster access, e.g. for gameport.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/bug.h> /* WARN_ONCE */
#include <linux/pci.h>
@@ -2694,7 +2694,6 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip)
static int
snd_azf3328_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_azf3328 *chip = card->private_data;
u16 *saved_regs_ctrl_u16;
@@ -2720,29 +2719,15 @@ snd_azf3328_suspend(struct device *dev)
ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu);
snd_azf3328_suspend_regs(chip, chip->opl3_io,
ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int
snd_azf3328_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
const struct snd_azf3328 *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io,
ARRAY_SIZE(chip->saved_regs_game));
snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io,
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 058b9973c09c..5925b7170e25 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -690,8 +690,7 @@ static int snd_bt87x_free(struct snd_bt87x *chip)
snd_bt87x_stop(chip);
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->mmio)
- iounmap(chip->mmio);
+ iounmap(chip->mmio);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
kfree(chip);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 96af33965b51..dd75b7536fa2 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1910,7 +1910,6 @@ static void snd_ca0106_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_ca0106_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ca0106 *chip = card->private_data;
int i;
@@ -1923,30 +1922,15 @@ static int snd_ca0106_suspend(struct device *dev)
snd_ca0106_mixer_suspend(chip);
ca0106_stop_chip(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ca0106_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ca0106 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
ca0106_init_chip(chip, 1);
if (chip->details->ac97)
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 68c0eb0a2807..025805cba779 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -70,7 +70,7 @@
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/tlv.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "ca0106.h"
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index 4f9c2821bb31..2c5c28adbefd 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -64,13 +64,13 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/asoundef.h>
-#include <asm/io.h>
#include "ca0106.h"
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 85ed40339db9..1d0f2cad2f5a 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -20,7 +20,7 @@
/* Does not work. Warning may block system in capture mode */
/* #define USE_VAR48KRATE */
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -3347,7 +3347,6 @@ static unsigned char saved_mixers[] = {
static int snd_cmipci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cmipci *cm = card->private_data;
int i;
@@ -3366,29 +3365,15 @@ static int snd_cmipci_suspend(struct device *dev)
/* disable ints */
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cmipci_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cmipci *cm = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* reset / initialize to a sane state */
snd_cmipci_write(cm, CM_REG_INT_HLDCLR, 0);
snd_cmipci_ch_reset(cm, CM_CH_PLAY);
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 4c49b5c8a7b3..c296fd0dbc9c 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -19,7 +19,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -973,14 +973,11 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = {
.pointer = snd_cs4281_pointer,
};
-static int snd_cs4281_pcm(struct cs4281 *chip, int device,
- struct snd_pcm **rpcm)
+static int snd_cs4281_pcm(struct cs4281 *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -996,8 +993,6 @@ static int snd_cs4281_pcm(struct cs4281 *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 512*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1321,10 +1316,8 @@ static int snd_cs4281_free(struct cs4281 *chip)
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->ba0)
- iounmap(chip->ba0);
- if (chip->ba1)
- iounmap(chip->ba1);
+ iounmap(chip->ba0);
+ iounmap(chip->ba1);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
@@ -1788,14 +1781,11 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input =
.trigger = snd_cs4281_midi_input_trigger,
};
-static int snd_cs4281_midi(struct cs4281 *chip, int device,
- struct snd_rawmidi **rrawmidi)
+static int snd_cs4281_midi(struct cs4281 *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "CS4281", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "CS4281");
@@ -1804,8 +1794,6 @@ static int snd_cs4281_midi(struct cs4281 *chip, int device,
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
@@ -1941,11 +1929,11 @@ static int snd_cs4281_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
- if ((err = snd_cs4281_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs4281_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_cs4281_midi(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs4281_midi(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
@@ -2008,7 +1996,6 @@ static int saved_regs[SUSPEND_REGISTERS] = {
static int cs4281_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs4281 *chip = card->private_data;
u32 ulCLK;
@@ -2047,30 +2034,16 @@ static int cs4281_suspend(struct device *dev)
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK &= ~CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int cs4281_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs4281 *chip = card->private_data;
unsigned int i;
u32 ulCLK;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1);
ulCLK |= CLKCR1_CKRA;
snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 6a6858c07826..655fbea1692c 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -100,16 +100,16 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
}
card->private_data = chip;
chip->accept_valid = mmap_valid[dev];
- if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
- if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_rear(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_iec958(chip, 2)) < 0) {
snd_card_free(card);
return err;
}
@@ -120,13 +120,13 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
if (chip->nr_ac97_codecs ==2) {
- if ((err = snd_cs46xx_pcm_center_lfe(chip,3,NULL)) < 0) {
+ if ((err = snd_cs46xx_pcm_center_lfe(chip, 3)) < 0) {
snd_card_free(card);
return err;
}
}
#endif
- if ((err = snd_cs46xx_midi(chip, 0, NULL)) < 0) {
+ if ((err = snd_cs46xx_midi(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h
index c49a082c378b..9c9f89a8be5f 100644
--- a/sound/pci/cs46xx/cs46xx.h
+++ b/sound/pci/cs46xx/cs46xx.h
@@ -1737,12 +1737,12 @@ int snd_cs46xx_create(struct snd_card *card,
struct snd_cs46xx **rcodec);
extern const struct dev_pm_ops snd_cs46xx_pm;
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm);
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device);
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device);
int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device);
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rmidi);
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device);
int snd_cs46xx_start_dsp(struct snd_cs46xx *chip);
int snd_cs46xx_gameport(struct snd_cs46xx *chip);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 32b44f25b5c8..8d74004b1ed2 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -57,6 +57,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -65,8 +66,6 @@
#include <sound/pcm_params.h>
#include "cs46xx.h"
-#include <asm/io.h>
-
#include "cs46xx_lib.h"
#include "dsp_spos.h"
@@ -1778,13 +1777,11 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
#define MAX_PLAYBACK_CHANNELS 1
#endif
-int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm)
+int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
return err;
@@ -1801,23 +1798,16 @@ int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
return err;
@@ -1833,21 +1823,14 @@ int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - Center LFE", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
return err;
@@ -1863,21 +1846,14 @@ int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device,
- struct snd_pcm **rpcm)
+int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0)
return err;
@@ -1893,9 +1869,6 @@ int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
#endif
@@ -2724,13 +2697,11 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input =
.trigger = snd_cs46xx_midi_input_trigger,
};
-int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi)
+int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(chip->card, "CS46XX", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, "CS46XX");
@@ -2739,8 +2710,6 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rr
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = chip;
chip->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = NULL;
return 0;
}
@@ -2979,8 +2948,8 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
for (idx = 0; idx < 5; idx++) {
struct snd_cs46xx_region *region = &chip->region.idx[idx];
- if (region->remap_addr)
- iounmap(region->remap_addr);
+
+ iounmap(region->remap_addr);
release_and_free_resource(region->resource);
}
@@ -3804,7 +3773,6 @@ static unsigned int saved_regs[] = {
static int snd_cs46xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_cs46xx *chip = card->private_data;
int i, amp_saved;
@@ -3829,16 +3797,11 @@ static int snd_cs46xx_suspend(struct device *dev)
/* disable CLKRUN */
chip->active_ctrl(chip, -chip->amplifier);
chip->amplifier = amp_saved; /* restore the status */
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cs46xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_cs46xx *chip = card->private_data;
int amp_saved;
@@ -3847,15 +3810,6 @@ static int snd_cs46xx_resume(struct device *dev)
#endif
unsigned int tmp;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
amp_saved = chip->amplifier;
chip->amplifier = 0;
chip->active_ctrl(chip, 1); /* force to on */
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 1c4a0fb3ffef..5c99efb004c0 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -20,7 +20,7 @@
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 8284bc9b5858..2c90c0bded69 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -21,7 +21,7 @@
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index b1025507a467..0a8cf94c4858 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -223,7 +223,7 @@ static int snd_cs5530_create(struct snd_card *card,
return err;
}
- err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+ err = snd_sb16dsp_pcm(chip->sb, 0);
if (err < 0) {
dev_err(card->dev, "Could not create PCM\n");
snd_cs5530_free(chip);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 16288e4d338a..802c33f1cc59 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -27,7 +27,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index 34cc60057d0c..06ac5d8da362 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -57,7 +57,6 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
static int snd_cs5535audio_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
int i;
@@ -72,34 +71,17 @@ static int snd_cs5535audio_suspend(struct device *dev)
}
/* save important regs, then disable aclink in hw */
snd_cs5535audio_stop_hardware(cs5535au);
-
- if (pci_save_state(pci)) {
- dev_err(dev, "pci_save_state failed!\n");
- return -EIO;
- }
- pci_disable_device(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_cs5535audio_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
u32 tmp;
int timeout;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* set LNK_WRM_RST to reset AC link */
cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST);
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index b425aa8ee578..1cac55fd1139 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1985,10 +1985,7 @@ static int hw_card_shutdown(struct hw *hw)
free_irq(hw->irq, hw);
hw->irq = -1;
-
- if (hw->mem_base)
- iounmap(hw->mem_base);
-
+ iounmap(hw->mem_base);
hw->mem_base = NULL;
if (hw->io_base)
@@ -2099,20 +2096,11 @@ static int hw_suspend(struct hw *hw)
pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x0);
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
-
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
- struct pci_dev *pci = hw->pci;
-
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 253899d13790..955ad871e9a8 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -2110,10 +2110,7 @@ static int hw_card_shutdown(struct hw *hw)
free_irq(hw->irq, hw);
hw->irq = -1;
-
- if (hw->mem_base)
- iounmap(hw->mem_base);
-
+ iounmap(hw->mem_base);
hw->mem_base = NULL;
if (hw->io_base)
@@ -2209,24 +2206,12 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
#ifdef CONFIG_PM_SLEEP
static int hw_suspend(struct hw *hw)
{
- struct pci_dev *pci = hw->pci;
-
hw_card_stop(hw);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
-
return 0;
}
static int hw_resume(struct hw *hw, struct card_conf *info)
{
- struct pci_dev *pci = hw->pci;
-
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
/* Re-initialize card hardware. */
return hw_card_init(hw, info);
}
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c
index 4632946205a8..c95da6301677 100644
--- a/sound/pci/echoaudio/darla20.c
+++ b/sound/pci/echoaudio/darla20.c
@@ -43,6 +43,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -51,7 +52,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c
index f81c839cc887..3013b4daa19e 100644
--- a/sound/pci/echoaudio/darla24.c
+++ b/sound/pci/echoaudio/darla24.c
@@ -47,6 +47,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -55,7 +56,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c
index 3a5346c33d76..1f34a07b0b19 100644
--- a/sound/pci/echoaudio/echo3g.c
+++ b/sound/pci/echoaudio/echo3g.c
@@ -54,6 +54,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -63,7 +64,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 21228adaa70c..a962de03ebb6 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1872,12 +1872,8 @@ static int snd_echo_free(struct echoaudio *chip)
if (chip->comm_page)
snd_dma_free_pages(&chip->commpage_dma_buf);
- if (chip->dsp_registers)
- iounmap(chip->dsp_registers);
-
+ iounmap(chip->dsp_registers);
release_and_free_resource(chip->iores);
-
-
pci_disable_device(chip->pci);
/* release chip data */
@@ -2162,7 +2158,6 @@ ctl_error:
static int snd_echo_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct echoaudio *chip = dev_get_drvdata(dev);
snd_pcm_suspend_all(chip->analog_pcm);
@@ -2188,9 +2183,6 @@ static int snd_echo_suspend(struct device *dev)
chip->dsp_code = NULL;
free_irq(chip->irq, chip);
chip->irq = -1;
- pci_save_state(pci);
- pci_disable_device(pci);
-
return 0;
}
@@ -2204,7 +2196,6 @@ static int snd_echo_resume(struct device *dev)
u32 pipe_alloc_mask;
int err;
- pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
if (commpage_bak == NULL)
return -ENOMEM;
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c
index 9cb81c500824..4fa32a2e97db 100644
--- a/sound/pci/echoaudio/gina20.c
+++ b/sound/pci/echoaudio/gina20.c
@@ -47,6 +47,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -55,7 +56,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c
index 35d3e6eac990..b1bcacaef257 100644
--- a/sound/pci/echoaudio/gina24.c
+++ b/sound/pci/echoaudio/gina24.c
@@ -53,6 +53,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -61,7 +62,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c
index 8d91842d1268..175af9b1435f 100644
--- a/sound/pci/echoaudio/indigo.c
+++ b/sound/pci/echoaudio/indigo.c
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -53,7 +54,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c
index 289cb969f5b9..8c60314e4901 100644
--- a/sound/pci/echoaudio/indigodj.c
+++ b/sound/pci/echoaudio/indigodj.c
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -53,7 +54,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c
index 405a3f2e496f..f7618edfd79c 100644
--- a/sound/pci/echoaudio/indigoio.c
+++ b/sound/pci/echoaudio/indigoio.c
@@ -46,6 +46,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -54,7 +55,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c
index b392dd776b71..12e5d2164dc4 100644
--- a/sound/pci/echoaudio/layla20.c
+++ b/sound/pci/echoaudio/layla20.c
@@ -52,6 +52,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -61,7 +62,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c
index bc7f730b0ec6..6e4023728ef5 100644
--- a/sound/pci/echoaudio/layla24.c
+++ b/sound/pci/echoaudio/layla24.c
@@ -54,6 +54,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -63,7 +64,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c
index 27a9a6e5db2d..2f7562f1aefb 100644
--- a/sound/pci/echoaudio/mia.c
+++ b/sound/pci/echoaudio/mia.c
@@ -53,6 +53,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -62,7 +63,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index d913749d154a..a8fe58335ddc 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -257,9 +257,8 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
spin_lock_irq(&chip->lock);
if (up) {
if (!chip->tinuse) {
- init_timer(&chip->timer);
- chip->timer.function = snd_echo_midi_output_write;
- chip->timer.data = (unsigned long)chip;
+ setup_timer(&chip->timer, snd_echo_midi_output_write,
+ (unsigned long)chip);
chip->tinuse = 1;
}
} else {
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c
index 3d13875c303d..34d499466393 100644
--- a/sound/pci/echoaudio/mona.c
+++ b/sound/pci/echoaudio/mona.c
@@ -51,6 +51,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -59,7 +60,6 @@
#include <sound/pcm_params.h>
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <linux/atomic.h>
#include "echoaudio.h"
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 4c171636efcd..37d0220a094c 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -132,11 +132,11 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
goto error;
card->private_data = emu;
emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
- if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm(emu, 0)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_mic(emu, 1)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_efx(emu, 2)) < 0)
goto error;
/* This stores the periods table. */
if (emu->card_capabilities->ca0151_chip) { /* P16V */
@@ -151,10 +151,10 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
if ((err = snd_emu10k1_timer(emu, 0)) < 0)
goto error;
- if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0)
+ if ((err = snd_emu10k1_pcm_multi(emu, 3)) < 0)
goto error;
if (emu->card_capabilities->ca0151_chip) { /* P16V */
- if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0)
+ if ((err = snd_p16v_pcm(emu, 4)) < 0)
goto error;
}
if (emu->audigy) {
@@ -164,7 +164,7 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
if ((err = snd_emu10k1_midi(emu)) < 0)
goto error;
}
- if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0)
+ if ((err = snd_emu10k1_fx8010_new(emu, 0)) < 0)
goto error;
#ifdef ENABLE_SYNTH
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
@@ -210,7 +210,6 @@ static void snd_card_emu10k1_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_emu10k1_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_emu10k1 *emu = card->private_data;
@@ -232,28 +231,14 @@ static int snd_emu10k1_suspend(struct device *dev)
snd_p16v_suspend(emu);
snd_emu10k1_done(emu);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_emu10k1_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_emu10k1 *emu = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_emu10k1_resume_init(emu);
snd_emu10k1_efx_resume(emu);
snd_ac97_resume(emu->ac97);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 15933f92f63a..6d1b98d14327 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -847,15 +847,13 @@ static const struct snd_pcm_chmap_elem clfe_map[] = {
{ }
};
-static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm)
+static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device)
{
struct snd_pcm *pcm;
const struct snd_pcm_chmap_elem *map = NULL;
int err;
int capture = 0;
- if (rpcm)
- *rpcm = NULL;
if (device == 0)
capture = 1;
@@ -896,15 +894,8 @@ static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **r
snd_dma_pci_data(emu->pci),
32*1024, 32*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, map, 2,
1 << 2, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
-
- return 0;
}
static int snd_emu10k1x_create(struct snd_card *card,
@@ -1583,15 +1574,15 @@ static int snd_emu10k1x_probe(struct pci_dev *pci,
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) {
+ if ((err = snd_emu10k1x_pcm(chip, 2)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index eb5c0aba41c1..56fc47bd6dba 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -2641,14 +2641,11 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file)
return 0;
}
-int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device,
- struct snd_hwdep **rhwdep)
+int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device)
{
struct snd_hwdep *hw;
int err;
- if (rhwdep)
- *rhwdep = NULL;
if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0)
return err;
strcpy(hw->name, "EMU10K1 (FX8010)");
@@ -2657,8 +2654,6 @@ int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device,
hw->ops.ioctl = snd_emu10k1_fx8010_ioctl;
hw->ops.release = snd_emu10k1_fx8010_release;
hw->private_data = emu;
- if (rhwdep)
- *rhwdep = hw;
return 0;
}
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index f82481bd2542..0dc07385af0e 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1400,15 +1400,12 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = {
.page = snd_pcm_sgbuf_ops_page,
};
-int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0)
return err;
@@ -1429,22 +1426,15 @@ int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
-int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0)
return err;
@@ -1461,9 +1451,6 @@ int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device,
if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0)
return err;
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
@@ -1479,15 +1466,11 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = {
.pointer = snd_emu10k1_capture_pointer,
};
-int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0)
return err;
@@ -1501,8 +1484,6 @@ int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1822,16 +1803,12 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = {
.ack = snd_emu10k1_fx8010_playback_transfer,
};
-int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device,
- struct snd_pcm **rpcm)
+int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_kcontrol *kctl;
int err;
- if (rpcm)
- *rpcm = NULL;
-
if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0)
return err;
@@ -1843,8 +1820,6 @@ int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device,
pcm->info_flags = 0;
strcpy(pcm->name, "Multichannel Capture/PT Playback");
emu->pcm_efx = pcm;
- if (rpcm)
- *rpcm = pcm;
/* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs
* to these
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 7ef3898a7806..3c60b433de9f 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -166,11 +166,8 @@ static struct snd_pcm_hardware snd_p16v_capture_hw = {
static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime)
{
struct snd_emu10k1_pcm *epcm = runtime->private_data;
-
- if (epcm) {
- /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */
- kfree(epcm);
- }
+
+ kfree(epcm);
}
/* open_playback callback */
@@ -640,7 +637,7 @@ int snd_p16v_free(struct snd_emu10k1 *chip)
return 0;
}
-int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
+int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)
{
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
@@ -649,8 +646,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
/* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */
emu->p16v_device_offset = device;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
return err;
@@ -694,9 +689,6 @@ int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm)
*/
}
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index d94cb3ca7a64..0dc44ebb0032 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -26,7 +26,7 @@
* by Kurt J. Bosch
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1268,14 +1268,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = {
{ }
};
-static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device,
- struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ensoniq->card, CHIP_NAME "/1", device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -1302,22 +1299,14 @@ static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device,
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 2, 0, NULL);
#endif
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
+ return err;
}
-static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device,
- struct snd_pcm **rpcm)
+static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ensoniq->card, CHIP_NAME "/2", device, 1, 0, &pcm);
if (err < 0)
return err;
@@ -1342,12 +1331,7 @@ static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device,
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
surround_map, 2, 0, NULL);
#endif
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
+ return err;
}
/*
@@ -2049,7 +2033,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
#ifdef CONFIG_PM_SLEEP
static int snd_ensoniq_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct ensoniq *ensoniq = card->private_data;
@@ -2070,28 +2053,14 @@ static int snd_ensoniq_suspend(struct device *dev)
udelay(100);
snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
#endif
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ensoniq_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct ensoniq *ensoniq = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_ensoniq_chip_init(ensoniq);
#ifdef CHIP1371
@@ -2362,14 +2331,11 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input =
.trigger = snd_ensoniq_midi_input_trigger,
};
-static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device,
- struct snd_rawmidi **rrawmidi)
+static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device)
{
struct snd_rawmidi *rmidi;
int err;
- if (rrawmidi)
- *rrawmidi = NULL;
if ((err = snd_rawmidi_new(ensoniq->card, "ES1370/1", device, 1, 1, &rmidi)) < 0)
return err;
strcpy(rmidi->name, CHIP_NAME);
@@ -2379,8 +2345,6 @@ static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device,
SNDRV_RAWMIDI_INFO_DUPLEX;
rmidi->private_data = ensoniq;
ensoniq->rmidi = rmidi;
- if (rrawmidi)
- *rrawmidi = rmidi;
return 0;
}
@@ -2462,15 +2426,15 @@ static int snd_audiopci_probe(struct pci_dev *pci,
return err;
}
#endif
- if ((err = snd_ensoniq_pcm(ensoniq, 0, NULL)) < 0) {
+ if ((err = snd_ensoniq_pcm(ensoniq, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ensoniq_pcm2(ensoniq, 1, NULL)) < 0) {
+ if ((err = snd_ensoniq_pcm2(ensoniq, 1)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ensoniq_midi(ensoniq, 0, NULL)) < 0) {
+ if ((err = snd_ensoniq_midi(ensoniq, 0)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 0fc46eb4e251..e1858d9d23d8 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -55,6 +55,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -63,8 +64,6 @@
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaromir Koutek <miri@punknet.cz>");
MODULE_DESCRIPTION("ESS Solo-1");
MODULE_LICENSE("GPL");
@@ -1454,7 +1453,6 @@ static unsigned char saved_regs[SAVED_REG_SIZE+1] = {
static int es1938_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1938 *chip = card->private_data;
unsigned char *s, *d;
@@ -1471,9 +1469,6 @@ static int es1938_suspend(struct device *dev)
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
@@ -1484,14 +1479,6 @@ static int es1938_resume(struct device *dev)
struct es1938 *chip = card->private_data;
unsigned char *s, *d;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
-
if (request_irq(pci->irq, snd_es1938_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
dev_err(dev, "unable to grab IRQ %d, disabling device\n",
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 6039700f8579..059f3846d7b8 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -94,7 +94,7 @@
* places.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -2383,7 +2383,6 @@ static void snd_es1968_start_irq(struct es1968 *chip)
*/
static int es1968_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1968 *chip = card->private_data;
@@ -2396,16 +2395,11 @@ static int es1968_suspend(struct device *dev)
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
snd_es1968_bob_stop(chip);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int es1968_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct es1968 *chip = card->private_data;
struct esschan *es;
@@ -2413,16 +2407,6 @@ static int es1968_resume(struct device *dev)
if (! chip->do_pm)
return 0;
- /* restore all our config */
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_es1968_chip_init(chip);
/* need to restore the base pointers.. */
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index d167afffce5f..1fdd92b6f18f 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -2,8 +2,6 @@
* The driver for the ForteMedia FM801 based soundcards
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
- * Support FM only card by Andy Shevchenko <andy@smile.org.ua>
- *
* 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
@@ -14,10 +12,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
- *
*/
#include <linux/delay.h>
@@ -704,13 +698,11 @@ static struct snd_pcm_ops snd_fm801_capture_ops = {
.pointer = snd_fm801_capture_pointer,
};
-static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm)
+static int snd_fm801_pcm(struct fm801 *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "FM801", device, 1, 1, &pcm)) < 0)
return err;
@@ -726,16 +718,10 @@ static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm)
snd_dma_pci_data(chip->pci),
chip->multichannel ? 128*1024 : 64*1024, 128*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_alt_chmaps,
chip->multichannel ? 6 : 2, 0,
NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
/*
@@ -1186,12 +1172,6 @@ static int snd_fm801_free(struct fm801 *chip)
v4l2_device_unregister(&chip->v4l2_dev);
}
#endif
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
- pci_release_regions(chip->pci);
- pci_disable_device(chip->pci);
-
- kfree(chip);
return 0;
}
@@ -1214,28 +1194,23 @@ static int snd_fm801_create(struct snd_card *card,
};
*rchip = NULL;
- if ((err = pci_enable_device(pci)) < 0)
+ if ((err = pcim_enable_device(pci)) < 0)
return err;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL) {
- pci_disable_device(pci);
+ chip = devm_kzalloc(&pci->dev, sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
return -ENOMEM;
- }
spin_lock_init(&chip->reg_lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->tea575x_tuner = tea575x_tuner;
- if ((err = pci_request_regions(pci, "FM801")) < 0) {
- kfree(chip);
- pci_disable_device(pci);
+ if ((err = pci_request_regions(pci, "FM801")) < 0)
return err;
- }
chip->port = pci_resource_start(pci, 0);
if ((tea575x_tuner & TUNER_ONLY) == 0) {
- if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED,
- KBUILD_MODNAME, chip)) {
- dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq);
+ if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_fm801_free(chip);
return -EBUSY;
}
@@ -1250,12 +1225,6 @@ static int snd_fm801_create(struct snd_card *card,
/* init might set tuner access method */
tea575x_tuner = chip->tea575x_tuner;
- if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) {
- pci_clear_master(pci);
- free_irq(chip->irq, chip);
- chip->irq = -1;
- }
-
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_fm801_free(chip);
return err;
@@ -1340,7 +1309,7 @@ static int snd_card_fm801_probe(struct pci_dev *pci,
if (chip->tea575x_tuner & TUNER_ONLY)
goto __fm801_tuner_only;
- if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_fm801_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
@@ -1392,7 +1361,6 @@ static unsigned char saved_regs[] = {
static int snd_fm801_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct fm801 *chip = card->private_data;
int i;
@@ -1404,29 +1372,15 @@ static int snd_fm801_suspend(struct device *dev)
for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
chip->saved_regs[i] = inw(chip->port + saved_regs[i]);
/* FIXME: tea575x suspend */
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_fm801_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct fm801 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_fm801_chip_init(chip, 1);
snd_ac97_resume(chip->ac97);
snd_ac97_resume(chip->ac97_sec);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index ebf4c2fb99df..7f0f2c5a4e97 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -107,6 +107,7 @@ config SND_HDA_PATCH_LOADER
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC
+ select INPUT
help
Say Y or M here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 1ede82200ee5..3f8706bb3d16 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -409,10 +409,10 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
/*
* debug prints of the parsed results
*/
- codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
- cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
- cfg->line_out_pins[2], cfg->line_out_pins[3],
- cfg->line_out_pins[4],
+ codec_info(codec, "autoconfig for %s: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+ codec->chip_name, cfg->line_outs, cfg->line_out_pins[0],
+ cfg->line_out_pins[1], cfg->line_out_pins[2],
+ cfg->line_out_pins[3], cfg->line_out_pins[4],
cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
(cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
"speaker" : "line"));
@@ -920,6 +920,8 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
codec->fixup_id = pq->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
codec->fixup_name = pq->name;
+ codec_dbg(codec, "%s: picked fixup %s (pin match)\n",
+ codec->chip_name, codec->fixup_name);
#endif
codec->fixup_list = fixlist;
return;
@@ -960,6 +962,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
codec->fixup_list = NULL;
codec->fixup_name = NULL;
codec->fixup_id = HDA_FIXUP_ID_NO_FIXUP;
+ codec_dbg(codec, "%s: picked no fixup (nofixup specified)\n",
+ codec->chip_name);
return;
}
@@ -969,6 +973,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
codec->fixup_id = models->id;
codec->fixup_name = models->name;
codec->fixup_list = fixlist;
+ codec_dbg(codec, "%s: picked fixup %s (model specified)\n",
+ codec->chip_name, codec->fixup_name);
return;
}
models++;
@@ -980,6 +986,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
id = q->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
+ codec_dbg(codec, "%s: picked fixup %s (PCI SSID%s)\n",
+ codec->chip_name, name, q->subdevice_mask ? "" : " - vendor generic");
#endif
}
}
@@ -992,6 +1000,8 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
id = q->value;
#ifdef CONFIG_SND_DEBUG_VERBOSE
name = q->name;
+ codec_dbg(codec, "%s: picked fixup %s (codec SSID)\n",
+ codec->chip_name, name);
#endif
break;
}
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 0cfc9c8c4b4e..a2ce773bdc62 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -657,6 +657,9 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits);
if (start) {
azx_timecounter_init(substream, 0, 0);
+ snd_pcm_gettime(substream->runtime, &substream->runtime->trigger_tstamp);
+ substream->runtime->trigger_tstamp_latched = true;
+
if (nsync > 1) {
cycle_t cycle_last;
@@ -939,7 +942,8 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec,
chip->card->dev,
size, MAX_PREALLOC_SIZE);
/* link to codec */
- pcm->dev = &codec->dev;
+ for (s = 0; s < 2; s++)
+ pcm->streams[s].dev.parent = &codec->dev;
return 0;
}
@@ -957,7 +961,6 @@ static int azx_alloc_cmd_io(struct azx *chip)
dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n");
return err;
}
-EXPORT_SYMBOL_GPL(azx_alloc_cmd_io);
static void azx_init_cmd_io(struct azx *chip)
{
@@ -1022,7 +1025,6 @@ static void azx_init_cmd_io(struct azx *chip)
azx_writeb(chip, RIRBCTL, AZX_RBCTL_DMA_EN | AZX_RBCTL_IRQ_EN);
spin_unlock_irq(&chip->reg_lock);
}
-EXPORT_SYMBOL_GPL(azx_init_cmd_io);
static void azx_free_cmd_io(struct azx *chip)
{
@@ -1032,7 +1034,6 @@ static void azx_free_cmd_io(struct azx *chip)
azx_writeb(chip, CORBCTL, 0);
spin_unlock_irq(&chip->reg_lock);
}
-EXPORT_SYMBOL_GPL(azx_free_cmd_io);
static unsigned int azx_command_addr(u32 cmd)
{
@@ -1312,7 +1313,6 @@ static int azx_send_cmd(struct hda_bus *bus, unsigned int val)
else
return azx_corb_send_cmd(bus, val);
}
-EXPORT_SYMBOL_GPL(azx_send_cmd);
/* get a response */
static unsigned int azx_get_response(struct hda_bus *bus,
@@ -1326,7 +1326,6 @@ static unsigned int azx_get_response(struct hda_bus *bus,
else
return azx_rirb_get_response(bus, addr);
}
-EXPORT_SYMBOL_GPL(azx_get_response);
#ifdef CONFIG_SND_HDA_DSP_LOADER
/*
@@ -1993,4 +1992,4 @@ void azx_notifier_unregister(struct azx *chip)
EXPORT_SYMBOL_GPL(azx_notifier_unregister);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Common HDA driver funcitons");
+MODULE_DESCRIPTION("Common HDA driver functions");
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 014a7849e8fd..11b5a42b4ec8 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -109,7 +109,6 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
hwdep->iface = SNDRV_HWDEP_IFACE_HDA;
hwdep->private_data = codec;
hwdep->exclusive = 1;
- hwdep->groups = snd_hda_dev_attr_groups;
hwdep->ops.open = hda_hwdep_open;
hwdep->ops.ioctl = hda_hwdep_ioctl;
@@ -118,7 +117,11 @@ int snd_hda_create_hwdep(struct hda_codec *codec)
#endif
/* link to codec */
- hwdep->dev = &codec->dev;
+ hwdep->dev.parent = &codec->dev;
+
+ /* for sysfs */
+ hwdep->dev.groups = snd_hda_dev_attr_groups;
+ dev_set_drvdata(&hwdep->dev, codec);
return 0;
}
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
index d4d0375ac181..714894527e06 100644
--- a/sound/pci/hda/hda_i915.c
+++ b/sound/pci/hda/hda_i915.c
@@ -18,10 +18,12 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
#include <sound/core.h>
-#include <drm/i915_powerwell.h>
#include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
/* Intel HSW/BDW display HDA controller Extended Mode registers.
* EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
@@ -31,32 +33,33 @@
#define AZX_REG_EM4 0x100c
#define AZX_REG_EM5 0x1010
-static int (*get_power)(void);
-static int (*put_power)(void);
-static int (*get_cdclk)(void);
-
-int hda_display_power(bool enable)
+int hda_display_power(struct hda_intel *hda, bool enable)
{
- if (!get_power || !put_power)
+ struct i915_audio_component *acomp = &hda->audio_component;
+
+ if (!acomp->ops)
return -ENODEV;
- pr_debug("HDA display power %s \n",
- enable ? "Enable" : "Disable");
+ dev_dbg(&hda->chip.pci->dev, "display power %s\n",
+ enable ? "enable" : "disable");
if (enable)
- return get_power();
+ acomp->ops->get_power(acomp->dev);
else
- return put_power();
+ acomp->ops->put_power(acomp->dev);
+
+ return 0;
}
-void haswell_set_bclk(struct azx *chip)
+void haswell_set_bclk(struct hda_intel *hda)
{
int cdclk_freq;
unsigned int bclk_m, bclk_n;
+ struct i915_audio_component *acomp = &hda->audio_component;
- if (!get_cdclk)
+ if (!acomp->ops)
return;
- cdclk_freq = get_cdclk();
+ cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
switch (cdclk_freq) {
case 337500:
bclk_m = 16;
@@ -80,51 +83,108 @@ void haswell_set_bclk(struct azx *chip)
break;
}
- azx_writew(chip, EM4, bclk_m);
- azx_writew(chip, EM5, bclk_n);
+ azx_writew(&hda->chip, EM4, bclk_m);
+ azx_writew(&hda->chip, EM5, bclk_n);
}
-
-int hda_i915_init(void)
+static int hda_component_master_bind(struct device *dev)
{
- int err = 0;
-
- get_power = symbol_request(i915_request_power_well);
- if (!get_power) {
- pr_warn("hda-i915: get_power symbol get fail\n");
- return -ENODEV;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct i915_audio_component *acomp = &hda->audio_component;
+ int ret;
+
+ ret = component_bind_all(dev, acomp);
+ if (ret < 0)
+ return ret;
+
+ if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
+ acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
+ ret = -EINVAL;
+ goto out_unbind;
}
- put_power = symbol_request(i915_release_power_well);
- if (!put_power) {
- symbol_put(i915_request_power_well);
- get_power = NULL;
- return -ENODEV;
+ /*
+ * Atm, we don't support dynamic unbinding initiated by the child
+ * component, so pin its containing module until we unbind.
+ */
+ if (!try_module_get(acomp->ops->owner)) {
+ ret = -ENODEV;
+ goto out_unbind;
}
- get_cdclk = symbol_request(i915_get_cdclk_freq);
- if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
- pr_warn("hda-i915: get_cdclk symbol get fail\n");
+ return 0;
- pr_debug("HDA driver get symbol successfully from i915 module\n");
+out_unbind:
+ component_unbind_all(dev, acomp);
- return err;
+ return ret;
}
-int hda_i915_exit(void)
+static void hda_component_master_unbind(struct device *dev)
{
- if (get_power) {
- symbol_put(i915_request_power_well);
- get_power = NULL;
- }
- if (put_power) {
- symbol_put(i915_release_power_well);
- put_power = NULL;
- }
- if (get_cdclk) {
- symbol_put(i915_get_cdclk_freq);
- get_cdclk = NULL;
+ struct snd_card *card = dev_get_drvdata(dev);
+ struct azx *chip = card->private_data;
+ struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct i915_audio_component *acomp = &hda->audio_component;
+
+ module_put(acomp->ops->owner);
+ component_unbind_all(dev, acomp);
+ WARN_ON(acomp->ops || acomp->dev);
+}
+
+static const struct component_master_ops hda_component_master_ops = {
+ .bind = hda_component_master_bind,
+ .unbind = hda_component_master_unbind,
+};
+
+static int hda_component_master_match(struct device *dev, void *data)
+{
+ /* i915 is the only supported component */
+ return !strcmp(dev->driver->name, "i915");
+}
+
+int hda_i915_init(struct hda_intel *hda)
+{
+ struct component_match *match = NULL;
+ struct device *dev = &hda->chip.pci->dev;
+ struct i915_audio_component *acomp = &hda->audio_component;
+ int ret;
+
+ component_match_add(dev, &match, hda_component_master_match, hda);
+ ret = component_master_add_with_match(dev, &hda_component_master_ops,
+ match);
+ if (ret < 0)
+ goto out_err;
+
+ /*
+ * Atm, we don't support deferring the component binding, so make sure
+ * i915 is loaded and that the binding successfully completes.
+ */
+ request_module("i915");
+
+ if (!acomp->ops) {
+ ret = -ENODEV;
+ goto out_master_del;
}
+ dev_dbg(dev, "bound to i915 component master\n");
+
+ return 0;
+out_master_del:
+ component_master_del(dev, &hda_component_master_ops);
+out_err:
+ dev_err(dev, "failed to add i915 component master (%d)\n", ret);
+
+ return ret;
+}
+
+int hda_i915_exit(struct hda_intel *hda)
+{
+ struct device *dev = &hda->chip.pci->dev;
+
+ component_master_del(dev, &hda_component_master_ops);
+
return 0;
}
diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h
deleted file mode 100644
index e6072c627583..000000000000
--- a/sound/pci/hda/hda_i915.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- *
- * 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.
- */
-#ifndef __SOUND_HDA_I915_H
-#define __SOUND_HDA_I915_H
-
-#ifdef CONFIG_SND_HDA_I915
-int hda_display_power(bool enable);
-void haswell_set_bclk(struct azx *chip);
-int hda_i915_init(void);
-int hda_i915_exit(void);
-#else
-static inline int hda_display_power(bool enable) { return 0; }
-static inline void haswell_set_bclk(struct azx *chip) { return; }
-static inline int hda_i915_init(void)
-{
- return -ENODEV;
-}
-static inline int hda_i915_exit(void)
-{
- return 0;
-}
-#endif
-
-#endif
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index d426a0bd6a5f..4ca3d5d02436 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -63,7 +63,7 @@
#include "hda_codec.h"
#include "hda_controller.h"
#include "hda_priv.h"
-#include "hda_i915.h"
+#include "hda_intel.h"
/* position fix mode */
enum {
@@ -354,31 +354,6 @@ static char *driver_short_names[] = {
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
-struct hda_intel {
- struct azx chip;
-
- /* for pending irqs */
- struct work_struct irq_pending_work;
-
- /* sync probing */
- struct completion probe_wait;
- struct work_struct probe_work;
-
- /* card list (for power_save trigger) */
- struct list_head list;
-
- /* extra flags */
- unsigned int irq_pending_warned:1;
-
- /* VGA-switcheroo setup */
- unsigned int use_vga_switcheroo:1;
- unsigned int vga_switcheroo_registered:1;
- unsigned int init_failed:1; /* delayed init failed */
-
- /* secondary power domain for hdmi audio under vga device */
- struct dev_pm_domain hdmi_pm_domain;
-};
-
#ifdef CONFIG_X86
static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
{
@@ -795,7 +770,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
*/
static int azx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
struct hda_intel *hda;
@@ -824,11 +798,8 @@ static int azx_suspend(struct device *dev)
if (chip->msi)
pci_disable_msi(chip->pci);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_display_power(false);
+ hda_display_power(hda, false);
return 0;
}
@@ -848,18 +819,9 @@ static int azx_resume(struct device *dev)
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(true);
- haswell_set_bclk(chip);
- }
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(chip->card->dev,
- "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
+ hda_display_power(hda, true);
+ haswell_set_bclk(hda);
}
- pci_set_master(pci);
if (chip->msi)
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
@@ -901,7 +863,7 @@ static int azx_runtime_suspend(struct device *dev)
azx_enter_link_reset(chip);
azx_clear_irq_pending(chip);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- hda_display_power(false);
+ hda_display_power(hda, false);
return 0;
}
@@ -927,8 +889,8 @@ static int azx_runtime_resume(struct device *dev)
return 0;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(true);
- haswell_set_bclk(chip);
+ hda_display_power(hda, true);
+ haswell_set_bclk(hda);
}
/* Read STATESTS before controller reset */
@@ -1138,8 +1100,7 @@ static int azx_free(struct azx *chip)
free_irq(chip->irq, (void*)chip);
if (chip->msi)
pci_disable_msi(chip->pci);
- if (chip->remap_addr)
- iounmap(chip->remap_addr);
+ iounmap(chip->remap_addr);
azx_free_stream_pages(chip);
if (chip->region_requested)
@@ -1150,8 +1111,8 @@ static int azx_free(struct azx *chip)
release_firmware(chip->fw);
#endif
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
- hda_display_power(false);
- hda_i915_exit();
+ hda_display_power(hda, false);
+ hda_i915_exit(hda);
}
kfree(hda);
@@ -1629,8 +1590,12 @@ static int azx_first_init(struct azx *chip)
/* initialize chip */
azx_init_pci(chip);
- if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
- haswell_set_bclk(chip);
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
+ struct hda_intel *hda;
+
+ hda = container_of(chip, struct hda_intel, chip);
+ haswell_set_bclk(hda);
+ }
azx_init_chip(chip, (probe_only[dev] & 2) == 0);
@@ -1910,13 +1875,10 @@ static int azx_probe_continue(struct azx *chip)
/* Request power well for Haswell HDA controller and codec */
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
#ifdef CONFIG_SND_HDA_I915
- err = hda_i915_init();
- if (err < 0) {
- dev_err(chip->card->dev,
- "Error request power-well from i915\n");
+ err = hda_i915_init(hda);
+ if (err < 0)
goto out_free;
- }
- err = hda_display_power(true);
+ err = hda_display_power(hda, true);
if (err < 0) {
dev_err(chip->card->dev,
"Cannot turn on display power on i915\n");
@@ -2004,7 +1966,7 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
new file mode 100644
index 000000000000..348611835476
--- /dev/null
+++ b/sound/pci/hda/hda_intel.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+#ifndef __SOUND_HDA_INTEL_H
+#define __SOUND_HDA_INTEL_H
+
+#include <drm/i915_component.h>
+#include "hda_priv.h"
+
+struct hda_intel {
+ struct azx chip;
+
+ /* for pending irqs */
+ struct work_struct irq_pending_work;
+
+ /* sync probing */
+ struct completion probe_wait;
+ struct work_struct probe_work;
+
+ /* card list (for power_save trigger) */
+ struct list_head list;
+
+ /* extra flags */
+ unsigned int irq_pending_warned:1;
+
+ /* VGA-switcheroo setup */
+ unsigned int use_vga_switcheroo:1;
+ unsigned int vga_switcheroo_registered:1;
+ unsigned int init_failed:1; /* delayed init failed */
+
+ /* secondary power domain for hdmi audio under vga device */
+ struct dev_pm_domain hdmi_pm_domain;
+
+ /* i915 component interface */
+ struct i915_audio_component audio_component;
+};
+
+#ifdef CONFIG_SND_HDA_I915
+int hda_display_power(struct hda_intel *hda, bool enable);
+void haswell_set_bclk(struct hda_intel *hda);
+int hda_i915_init(struct hda_intel *hda);
+int hda_i915_exit(struct hda_intel *hda);
+#else
+static inline int hda_display_power(struct hda_intel *hda, bool enable)
+{
+ return 0;
+}
+static inline void haswell_set_bclk(struct hda_intel *hda) { return; }
+static inline int hda_i915_init(struct hda_intel *hda)
+{
+ return -ENODEV;
+}
+static inline int hda_i915_exit(struct hda_intel *hda)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
index 166e3e84b963..daf458299753 100644
--- a/sound/pci/hda/hda_priv.h
+++ b/sound/pci/hda/hda_priv.h
@@ -15,7 +15,7 @@
#ifndef __SOUND_HDA_PRIV_H
#define __SOUND_HDA_PRIV_H
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
#include <sound/core.h>
#include <sound/pcm.h>
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 227990bc02e3..375e94f4cf52 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -329,8 +329,8 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hda->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(chip->remap_addr))
- return PTR_ERR(chip->remap_addr);
+ if (IS_ERR(hda->regs))
+ return PTR_ERR(hda->regs);
chip->remap_addr = hda->regs + HDA_BAR0;
chip->addr = res->start + HDA_BAR0;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index a9d78e275138..d285904cdb64 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -739,39 +739,6 @@ static int patch_ad1981(struct hda_codec *codec)
* E/F quad mic array
*/
-#ifdef ENABLE_AD_STATIC_QUIRKS
-static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
- spec->num_channel_mode);
-}
-
-static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode, spec->multiout.max_channels);
-}
-
-static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
- struct ad198x_spec *spec = codec->spec;
- int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
- spec->num_channel_mode,
- &spec->multiout.max_channels);
- if (err >= 0 && spec->need_dac_fix)
- spec->multiout.num_dacs = spec->multiout.max_channels / 2;
- return err;
-}
-#endif /* ENABLE_AD_STATIC_QUIRKS */
-
static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 65f1f4e18ea5..b2b24a8b3dac 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -29,6 +29,7 @@
#include <linux/pci.h>
#include <linux/dmi.h>
#include <linux/module.h>
+#include <linux/input.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
@@ -120,6 +121,7 @@ struct alc_spec {
hda_nid_t pll_nid;
unsigned int pll_coef_idx, pll_coef_bit;
unsigned int coef0;
+ struct input_dev *kb_dev;
};
/*
@@ -3472,6 +3474,79 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
}
}
+static void gpio2_mic_hotkey_event(struct hda_codec *codec,
+ struct hda_jack_callback *event)
+{
+ struct alc_spec *spec = codec->spec;
+
+ /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
+ send both key on and key off event for every interrupt. */
+ input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+ input_sync(spec->kb_dev);
+ input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+ input_sync(spec->kb_dev);
+}
+
+static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /* GPIO1 = set according to SKU external amp
+ GPIO2 = mic mute hotkey
+ GPIO3 = mute LED
+ GPIO4 = mic mute LED */
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
+ {}
+ };
+
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->kb_dev = input_allocate_device();
+ if (!spec->kb_dev) {
+ codec_err(codec, "Out of memory (input_allocate_device)\n");
+ return;
+ }
+ spec->kb_dev->name = "Microphone Mute Button";
+ spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+ spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
+ if (input_register_device(spec->kb_dev)) {
+ codec_err(codec, "input_register_device failed\n");
+ input_free_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ return;
+ }
+
+ snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_codec_write_cache(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
+ snd_hda_jack_detect_enable_callback(codec, codec->afg,
+ gpio2_mic_hotkey_event);
+
+ 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;
+ return;
+ }
+
+ if (!spec->kb_dev)
+ return;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PROBE:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ case HDA_FIXUP_ACT_FREE:
+ input_unregister_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ }
+}
+
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4341,6 +4416,8 @@ enum {
ALC282_FIXUP_ASPIRE_V5_PINS,
ALC280_FIXUP_HP_GPIO4,
ALC286_FIXUP_HP_GPIO_LED,
+ ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
+ ALC280_FIXUP_HP_DOCK_PINS,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -4814,6 +4891,21 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc286_fixup_hp_gpio_led,
},
+ [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
+ },
+ [ALC280_FIXUP_HP_DOCK_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x21011020 }, /* line-out */
+ { 0x1a, 0x01a1903c }, /* headset mic */
+ { 0x18, 0x2181103f }, /* line-in */
+ { },
+ },
+ .chained = true,
+ .chain_id = ALC280_FIXUP_HP_GPIO4
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4843,7 +4935,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
/* ALC282 */
+ SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
@@ -4856,6 +4950,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
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, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
+ SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS),
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),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 605d14003d25..87eff3173ce9 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -79,6 +79,7 @@ enum {
STAC_ALIENWARE_M17X,
STAC_92HD89XX_HP_FRONT_JACK,
STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
+ STAC_92HD73XX_ASUS_MOBO,
STAC_92HD73XX_MODELS
};
@@ -99,6 +100,7 @@ enum {
STAC_HP_ENVY_BASS,
STAC_HP_BNB13_EQ,
STAC_HP_ENVY_TS_BASS,
+ STAC_92HD83XXX_GPIO10_EAPD,
STAC_92HD83XXX_MODELS
};
@@ -1910,7 +1912,18 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
[STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
.type = HDA_FIXUP_PINS,
.v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
- }
+ },
+ [STAC_92HD73XX_ASUS_MOBO] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* enable 5.1 and SPDIF out */
+ { 0x0c, 0x01014411 },
+ { 0x0d, 0x01014410 },
+ { 0x0e, 0x01014412 },
+ { 0x22, 0x014b1180 },
+ { }
+ }
+ },
};
static const struct hda_model_fixup stac92hd73xx_models[] = {
@@ -1922,6 +1935,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
{ .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
{ .id = STAC_DELL_EQ, .name = "dell-eq" },
{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+ { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
{}
};
@@ -1974,6 +1988,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
"unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
+ STAC_92HD73XX_ASUS_MOBO),
{} /* terminator */
};
@@ -2141,6 +2157,19 @@ static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
spec->headset_jack = 1;
}
+static void stac92hd83xxx_fixup_gpio10_eapd(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ spec->eapd_mask = spec->gpio_mask = spec->gpio_dir =
+ spec->gpio_data = 0x10;
+ spec->eapd_switch = 0;
+}
+
static const struct hda_verb hp_bnb13_eq_verbs[] = {
/* 44.1KHz base */
{ 0x22, 0x7A6, 0x3E },
@@ -2656,6 +2685,10 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
{}
},
},
+ [STAC_92HD83XXX_GPIO10_EAPD] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = stac92hd83xxx_fixup_gpio10_eapd,
+ },
};
static const struct hda_model_fixup stac92hd83xxx_models[] = {
@@ -2861,6 +2894,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
"HP Mini", STAC_92HD83XXX_HP_LED),
SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_TOSHIBA, 0xfa91,
+ "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
{} /* terminator */
};
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c
index 3981823f9094..179ef7a5f0d1 100644
--- a/sound/pci/ice1712/ak4xxx.c
+++ b/sound/pci/ice1712/ak4xxx.c
@@ -21,7 +21,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index b039b46152c6..f7b1523e8a82 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -880,13 +880,11 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = {
.pointer = snd_ice1712_capture_pointer,
};
-static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 consumer", device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -902,22 +900,17 @@ static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm *
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci), 64*1024, 64*1024);
- if (rpcm)
- *rpcm = pcm;
-
dev_warn(ice->card->dev,
"Consumer PCM code does not work well at the moment --jk\n");
return 0;
}
-static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm);
if (err < 0)
return err;
@@ -932,9 +925,6 @@ static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pc
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = pcm;
-
return 0;
}
@@ -1260,13 +1250,11 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = {
.pointer = snd_ice1712_capture_pro_pointer,
};
-static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm)
+static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm);
if (err < 0)
return err;
@@ -1282,8 +1270,6 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd
snd_dma_pci_data(ice->pci), 256*1024, 256*1024);
ice->pcm_pro = pcm;
- if (rpcm)
- *rpcm = pcm;
if (ice->cs8427) {
/* assign channels to iec958 */
@@ -2691,14 +2677,14 @@ static int snd_ice1712_probe(struct pci_dev *pci,
c = &no_matched;
__found:
- err = snd_ice1712_pcm_profi(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm_profi(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
}
if (ice_has_con_ac97(ice)) {
- err = snd_ice1712_pcm(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2726,7 +2712,7 @@ static int snd_ice1712_probe(struct pci_dev *pci,
}
if (ice_has_con_ac97(ice)) {
- err = snd_ice1712_pcm_ds(ice, pcm_dev++, NULL);
+ err = snd_ice1712_pcm_ds(ice, pcm_dev++);
if (err < 0) {
snd_card_free(card);
return err;
@@ -2798,7 +2784,6 @@ static void snd_ice1712_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_ice1712_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
@@ -2820,16 +2805,11 @@ static int snd_ice1712_suspend(struct device *dev)
if (ice->pm_suspend)
ice->pm_suspend(ice);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_ice1712_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
int rate;
@@ -2837,16 +2817,6 @@ static int snd_ice1712_resume(struct device *dev)
if (!ice->pm_suspend_enabled)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
if (ice->cur_rate)
rate = ice->cur_rate;
else
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index d73da157ea14..0b22c00642bb 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2798,7 +2798,6 @@ static void snd_vt1724_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_vt1724_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
@@ -2821,32 +2820,17 @@ static int snd_vt1724_suspend(struct device *dev)
if (ice->pm_suspend)
ice->pm_suspend(ice);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_vt1724_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ice1712 *ice = card->private_data;
if (!ice->pm_suspend_enabled)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- snd_card_disconnect(card);
- return -EIO;
- }
-
- pci_set_master(pci);
-
snd_vt1724_chip_reset(ice);
if (snd_vt1724_chip_init(ice) < 0) {
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index a1536c1a7ed4..4f0213427152 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -491,15 +491,17 @@ static int juli_resume(struct snd_ice1712 *ice)
/* akm4358 un-reset, un-mute */
snd_akm4xxx_reset(ak, 0);
/* reinit ak4114 */
- snd_ak4114_reinit(spec->ak4114);
+ snd_ak4114_resume(spec->ak4114);
return 0;
}
static int juli_suspend(struct snd_ice1712 *ice)
{
struct snd_akm4xxx *ak = ice->akm;
+ struct juli_spec *spec = ice->spec;
/* akm4358 reset and soft-mute */
snd_akm4xxx_reset(ak, 1);
+ snd_ak4114_suspend(spec->ak4114);
return 0;
}
#endif
diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c
index 21b373b2e260..f7ac8d5e862c 100644
--- a/sound/pci/ice1712/wm8766.c
+++ b/sound/pci/ice1712/wm8766.c
@@ -183,22 +183,6 @@ void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac)
snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac);
}
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode)
-{
- u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK;
-
- mode &= WM8766_DAC3_MSTR_MASK;
- snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode);
-}
-
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power)
-{
- u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK;
-
- power &= WM8766_DAC3_POWER_MASK;
- snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power);
-}
-
void snd_wm8766_volume_restore(struct snd_wm8766 *wm)
{
u16 val = wm->regs[WM8766_REG_DACR1];
diff --git a/sound/pci/ice1712/wm8766.h b/sound/pci/ice1712/wm8766.h
index c119f84bd2c2..18c8d9d47b38 100644
--- a/sound/pci/ice1712/wm8766.h
+++ b/sound/pci/ice1712/wm8766.h
@@ -155,8 +155,6 @@ struct snd_wm8766 {
void snd_wm8766_init(struct snd_wm8766 *wm);
void snd_wm8766_resume(struct snd_wm8766 *wm);
void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac);
-void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode);
-void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power);
void snd_wm8766_volume_restore(struct snd_wm8766 *wm);
int snd_wm8766_build_controls(struct snd_wm8766 *wm);
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index e66c0da62014..ebd2fe4b4a57 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -452,21 +452,6 @@ void snd_wm8776_resume(struct snd_wm8776 *wm)
snd_wm8776_write(wm, i, wm->regs[i]);
}
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac)
-{
- snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac);
-}
-
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc)
-{
- snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc);
-}
-
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode)
-{
- snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode);
-}
-
void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power)
{
snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power);
diff --git a/sound/pci/ice1712/wm8776.h b/sound/pci/ice1712/wm8776.h
index 93a2d6971154..42acef05540c 100644
--- a/sound/pci/ice1712/wm8776.h
+++ b/sound/pci/ice1712/wm8776.h
@@ -216,9 +216,6 @@ struct snd_wm8776 {
void snd_wm8776_init(struct snd_wm8776 *wm);
void snd_wm8776_resume(struct snd_wm8776 *wm);
-void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac);
-void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc);
-void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode);
void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power);
void snd_wm8776_volume_restore(struct snd_wm8776 *wm);
int snd_wm8776_build_controls(struct snd_wm8776 *wm);
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 4a28252a42b9..2c5484eeb963 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -26,7 +26,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -2654,7 +2654,6 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
*/
static int intel8x0_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0 *chip = card->private_data;
int i;
@@ -2682,12 +2681,6 @@ static int intel8x0_suspend(struct device *dev)
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- /* The call below may disable built-in speaker on some laptops
- * after S2RAM. So, don't touch it.
- */
- /* pci_set_power_state(pci, PCI_D3hot); */
return 0;
}
@@ -2698,14 +2691,6 @@ static int intel8x0_resume(struct device *dev)
struct intel8x0 *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_intel8x0_chip_init(chip, 0);
if (request_irq(pci->irq, snd_intel8x0_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 6b40235be13c..7577f31cd504 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -23,7 +23,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1023,7 +1023,6 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)
*/
static int intel8x0m_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0m *chip = card->private_data;
int i;
@@ -1036,9 +1035,6 @@ static int intel8x0m_suspend(struct device *dev)
free_irq(chip->irq, chip);
chip->irq = -1;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
@@ -1048,14 +1044,6 @@ static int intel8x0m_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0m *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
if (request_irq(pci->irq, snd_intel8x0m_interrupt,
IRQF_SHARED, KBUILD_MODNAME, chip)) {
dev_err(dev, "unable to grab IRQ %d, disabling device\n",
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 59d21c9401d2..7acbc21d642a 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/firmware.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -36,8 +37,6 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
// ----------------------------------------------------------------------------
// Debug Stuff
// ----------------------------------------------------------------------------
@@ -585,8 +584,7 @@ static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212)
korg1212->sharedBufferPtr->cardCommand = 0xffffffff;
/* program the timer */
korg1212->stop_pending_cnt = HZ;
- korg1212->timer.expires = jiffies + 1;
- add_timer(&korg1212->timer);
+ mod_timer(&korg1212->timer, jiffies + 1);
}
}
@@ -617,8 +615,7 @@ static void snd_korg1212_timer_func(unsigned long data)
} else {
if (--korg1212->stop_pending_cnt > 0) {
/* reprogram timer */
- korg1212->timer.expires = jiffies + 1;
- add_timer(&korg1212->timer);
+ mod_timer(&korg1212->timer, jiffies + 1);
} else {
snd_printd("korg1212_timer_func timeout\n");
korg1212->sharedBufferPtr->cardCommand = 0;
@@ -2172,9 +2169,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
init_waitqueue_head(&korg1212->wait);
spin_lock_init(&korg1212->lock);
mutex_init(&korg1212->open_mutex);
- init_timer(&korg1212->timer);
- korg1212->timer.function = snd_korg1212_timer_func;
- korg1212->timer.data = (unsigned long)korg1212;
+ setup_timer(&korg1212->timer, snd_korg1212_timer_func,
+ (unsigned long)korg1212);
korg1212->irq = -1;
korg1212->clkSource = K1212_CLKIDX_Local;
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 4cf4be5ef82a..9ff600084973 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -551,10 +551,8 @@ static void lola_free(struct lola *chip)
lola_free_mixer(chip);
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
- if (chip->bar[0].remap_addr)
- iounmap(chip->bar[0].remap_addr);
- if (chip->bar[1].remap_addr)
- iounmap(chip->bar[1].remap_addr);
+ iounmap(chip->bar[0].remap_addr);
+ iounmap(chip->bar[1].remap_addr);
if (chip->rb.area)
snd_dma_free_pages(&chip->rb);
pci_release_regions(chip->pci);
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 98823d11d485..9be660993bd0 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -31,7 +31,7 @@
#define CARD_NAME "ESS Maestro3/Allegro/Canyon3D-2"
#define DRIVER_NAME "Maestro3"
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -2395,7 +2395,6 @@ static int snd_m3_free(struct snd_m3 *chip)
#ifdef CONFIG_PM_SLEEP
static int m3_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_m3 *chip = card->private_data;
int i, dsp_index;
@@ -2421,16 +2420,11 @@ static int m3_suspend(struct device *dev)
for (i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
chip->suspend_mem[dsp_index++] =
snd_m3_assp_read(chip, MEMTYPE_INTERNAL_DATA, i);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int m3_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_m3 *chip = card->private_data;
int i, dsp_index;
@@ -2438,15 +2432,6 @@ static int m3_resume(struct device *dev)
if (chip->suspend_mem == NULL)
return 0;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
/* first lets just bring everything back. .*/
snd_m3_outw(chip, 0, 0x54);
snd_m3_outw(chip, 0, 0x56);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 1faf47e81570..c3a9f39f8d61 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1114,10 +1114,9 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
}
/* release the i/o ports */
- for (i = 0; i < 2; i++) {
- if (mgr->mem[i].virt)
- iounmap(mgr->mem[i].virt);
- }
+ for (i = 0; i < 2; ++i)
+ iounmap(mgr->mem[i].virt);
+
pci_release_regions(mgr->pci);
/* free flowarray */
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index fe80313674d9..dccf3db48fe0 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -23,8 +23,8 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/pci.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <sound/core.h>
#include "mixart.h"
#include "mixart_hwdep.h"
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 9996a4dead0f..5bfd3ac80db5 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -26,7 +26,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include "mixart.h"
#include "mixart_mixer.h"
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 4e41a4e29a1e..4735e27cc773 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -24,7 +24,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1392,7 +1392,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
*/
static int nm256_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct nm256 *chip = card->private_data;
@@ -1400,15 +1399,11 @@ static int nm256_suspend(struct device *dev)
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
chip->coeffs_current = 0;
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int nm256_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct nm256 *chip = card->private_data;
int i;
@@ -1416,15 +1411,6 @@ static int nm256_resume(struct device *dev)
/* Perform a full reset on the hardware */
chip->in_resume = 1;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_nm256_init_chip(chip);
/* restore ac97 */
@@ -1460,10 +1446,8 @@ static int snd_nm256_free(struct nm256 *chip)
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->cport)
- iounmap(chip->cport);
- if (chip->buffer)
- iounmap(chip->buffer);
+ iounmap(chip->cport);
+ iounmap(chip->buffer);
release_and_free_resource(chip->res_cport);
release_and_free_resource(chip->res_buffer);
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 8f4c409f7e45..ab085d753661 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,8 +1,10 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
+snd-se6x-objs := se6x.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o
obj-$(CONFIG_SND_OXYGEN) += snd-oxygen.o
+obj-$(CONFIG_SND_SE6X) += snd-se6x.o
obj-$(CONFIG_SND_VIRTUOSO) += snd-virtuoso.o
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index c10ab077afd8..293d0b9a50c3 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -35,7 +35,7 @@
#define CAPTURE_1_FROM_SPDIF 0x0080
#define CAPTURE_2_FROM_I2S_2 0x0100
#define CAPTURE_2_FROM_AC97_1 0x0200
- /* CAPTURE_3_FROM_I2S_3 not implemented */
+#define CAPTURE_3_FROM_I2S_3 0x0400
#define MIDI_OUTPUT 0x0800
#define MIDI_INPUT 0x1000
#define AC97_CD_INPUT 0x2000
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 4b8a32c37e31..c7851da37749 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -20,9 +20,9 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/export.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/mpu401.h>
-#include <asm/io.h>
#include "oxygen.h"
u8 oxygen_read8(struct oxygen *chip, unsigned int reg)
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index b67e30602473..ffff3b25fd73 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -319,11 +319,12 @@ static void oxygen_restore_eeprom(struct oxygen *chip,
static void configure_pcie_bridge(struct pci_dev *pci)
{
- enum { PEX811X, PI7C9X110 };
+ enum { PEX811X, PI7C9X110, XIO2001 };
static const struct pci_device_id bridge_ids[] = {
{ PCI_VDEVICE(PLX, 0x8111), .driver_data = PEX811X },
{ PCI_VDEVICE(PLX, 0x8112), .driver_data = PEX811X },
{ PCI_DEVICE(0x12d8, 0xe110), .driver_data = PI7C9X110 },
+ { PCI_VDEVICE(TI, 0x8240), .driver_data = XIO2001 },
{ }
};
struct pci_dev *bridge;
@@ -357,6 +358,14 @@ static void configure_pcie_bridge(struct pci_dev *pci)
tmp |= 1; /* park the PCI arbiter to the sound chip */
pci_write_config_dword(bridge, 0x40, tmp);
break;
+
+ case XIO2001: /* Texas Instruments XIO2001 PCIe/PCI bridge */
+ pci_read_config_dword(bridge, 0xe8, &tmp);
+ tmp &= ~0xf; /* request length limit: 64 bytes */
+ tmp &= ~(0xf << 8);
+ tmp |= 1 << 8; /* request count limit: one buffer */
+ pci_write_config_dword(bridge, 0xe8, tmp);
+ break;
}
}
@@ -441,9 +450,18 @@ static void oxygen_init(struct oxygen *chip)
oxygen_write16(chip, OXYGEN_I2S_B_FORMAT,
OXYGEN_I2S_MASTER |
OXYGEN_I2S_MUTE_MCLK);
- oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
- OXYGEN_I2S_MASTER |
- OXYGEN_I2S_MUTE_MCLK);
+ if (chip->model.device_config & CAPTURE_3_FROM_I2S_3)
+ oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+ OXYGEN_RATE_48000 |
+ chip->model.adc_i2s_format |
+ OXYGEN_I2S_MCLK(chip->model.adc_mclks) |
+ OXYGEN_I2S_BITS_16 |
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_BCLK_64);
+ else
+ oxygen_write16(chip, OXYGEN_I2S_C_FORMAT,
+ OXYGEN_I2S_MASTER |
+ OXYGEN_I2S_MUTE_MCLK);
oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL,
OXYGEN_SPDIF_OUT_ENABLE |
OXYGEN_SPDIF_LOOPBACK);
@@ -728,7 +746,6 @@ EXPORT_SYMBOL(oxygen_pci_remove);
#ifdef CONFIG_PM_SLEEP
static int oxygen_pci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i, saved_interrupt_mask;
@@ -736,8 +753,7 @@ static int oxygen_pci_suspend(struct device *dev)
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
for (i = 0; i < PCM_COUNT; ++i)
- if (chip->streams[i])
- snd_pcm_suspend(chip->streams[i]);
+ snd_pcm_suspend(chip->streams[i]);
if (chip->model.suspend)
chip->model.suspend(chip);
@@ -753,10 +769,6 @@ static int oxygen_pci_suspend(struct device *dev)
flush_work(&chip->spdif_input_bits_work);
flush_work(&chip->gpio_work);
chip->interrupt_mask = saved_interrupt_mask;
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
@@ -788,20 +800,10 @@ static void oxygen_restore_ac97(struct oxygen *chip, unsigned int codec)
static int oxygen_pci_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct oxygen *chip = card->private_data;
unsigned int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "cannot reenable device");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
oxygen_write16(chip, OXYGEN_DMA_STATUS, 0);
oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0);
for (i = 0; i < OXYGEN_IO_SIZE; ++i)
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index 5988e044c519..6492bca8c70f 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -786,6 +786,9 @@ static const struct snd_kcontrol_new controls[] = {
.get = upmix_get,
.put = upmix_put,
},
+};
+
+static const struct snd_kcontrol_new spdif_output_controls[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
@@ -938,6 +941,33 @@ static const struct {
},
},
{
+ .pcm_dev = CAPTURE_3_FROM_I2S_3,
+ .controls = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Input Monitor Playback Switch",
+ .index = 2,
+ .info = snd_ctl_boolean_mono_info,
+ .get = monitor_get,
+ .put = monitor_put,
+ .private_value = OXYGEN_ADC_MONITOR_C,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Input Monitor Playback Volume",
+ .index = 2,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = monitor_volume_info,
+ .get = monitor_get,
+ .put = monitor_put,
+ .private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
+ | (1 << 8),
+ .tlv = { .p = monitor_db_scale, },
+ },
+ },
+ },
+ {
.pcm_dev = CAPTURE_1_FROM_SPDIF,
.controls = {
{
@@ -1073,6 +1103,12 @@ int oxygen_mixer_init(struct oxygen *chip)
err = add_controls(chip, controls, ARRAY_SIZE(controls));
if (err < 0)
return err;
+ if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) {
+ err = add_controls(chip, spdif_output_controls,
+ ARRAY_SIZE(spdif_output_controls));
+ if (err < 0)
+ return err;
+ }
if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
err = add_controls(chip, spdif_input_controls,
ARRAY_SIZE(spdif_input_controls));
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c
index 02828240ba15..aa2ebd1d6d12 100644
--- a/sound/pci/oxygen/oxygen_pcm.c
+++ b/sound/pci/oxygen/oxygen_pcm.c
@@ -144,9 +144,11 @@ static int oxygen_open(struct snd_pcm_substream *substream,
runtime->hw = *oxygen_hardware[channel];
switch (channel) {
case PCM_C:
- runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_64000);
- runtime->hw.rate_min = 44100;
+ if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
+ runtime->hw.rates &= ~(SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_64000);
+ runtime->hw.rate_min = 44100;
+ }
/* fall through */
case PCM_A:
case PCM_B:
@@ -430,17 +432,36 @@ static int oxygen_rec_c_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct oxygen *chip = snd_pcm_substream_chip(substream);
+ bool is_spdif;
int err;
err = oxygen_hw_params(substream, hw_params);
if (err < 0)
return err;
+ is_spdif = chip->model.device_config & CAPTURE_1_FROM_SPDIF;
+
spin_lock_irq(&chip->reg_lock);
oxygen_write8_masked(chip, OXYGEN_REC_FORMAT,
oxygen_format(hw_params) << OXYGEN_REC_FORMAT_C_SHIFT,
OXYGEN_REC_FORMAT_C_MASK);
+ if (!is_spdif)
+ oxygen_write16_masked(chip, OXYGEN_I2S_C_FORMAT,
+ oxygen_rate(hw_params) |
+ chip->model.adc_i2s_format |
+ get_mclk(chip, PCM_B, hw_params) |
+ oxygen_i2s_bits(hw_params),
+ OXYGEN_I2S_RATE_MASK |
+ OXYGEN_I2S_FORMAT_MASK |
+ OXYGEN_I2S_MCLK_MASK |
+ OXYGEN_I2S_BITS_MASK);
spin_unlock_irq(&chip->reg_lock);
+
+ if (!is_spdif) {
+ mutex_lock(&chip->mutex);
+ chip->model.set_adc_params(chip, hw_params);
+ mutex_unlock(&chip->mutex);
+ }
return 0;
}
@@ -676,11 +697,6 @@ static struct snd_pcm_ops oxygen_ac97_ops = {
.pointer = oxygen_pointer,
};
-static void oxygen_pcm_free(struct snd_pcm *pcm)
-{
- snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
int oxygen_pcm_init(struct oxygen *chip)
{
struct snd_pcm *pcm;
@@ -705,7 +721,6 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, "Multichannel");
if (outs)
snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
@@ -734,7 +749,6 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_c_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, "Digital");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
@@ -765,12 +779,29 @@ int oxygen_pcm_init(struct oxygen *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
&oxygen_rec_b_ops);
pcm->private_data = chip;
- pcm->private_free = oxygen_pcm_free;
strcpy(pcm->name, outs ? "Front Panel" : "Analog 2");
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
DEFAULT_BUFFER_BYTES,
BUFFER_BYTES_MAX);
}
+
+ ins = !!(chip->model.device_config & CAPTURE_3_FROM_I2S_3);
+ if (ins) {
+ err = snd_pcm_new(chip->card, "Analog3", 3, 0, ins, &pcm);
+ if (err < 0)
+ return err;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &oxygen_rec_c_ops);
+ oxygen_write8_masked(chip, OXYGEN_REC_ROUTING,
+ OXYGEN_REC_C_ROUTE_I2S_ADC_3,
+ OXYGEN_REC_C_ROUTE_MASK);
+ pcm->private_data = chip;
+ strcpy(pcm->name, "Analog 3");
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci),
+ DEFAULT_BUFFER_BYTES,
+ BUFFER_BYTES_MAX);
+ }
return 0;
}
diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c
new file mode 100644
index 000000000000..f70d514c1084
--- /dev/null
+++ b/sound/pci/oxygen/se6x.c
@@ -0,0 +1,160 @@
+/*
+ * C-Media CMI8787 driver for the Studio Evolution SE6X
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CMI8787:
+ *
+ * SPI -> microcontroller (not actually used)
+ * GPIO 0 -> do.
+ * GPIO 2 -> do.
+ *
+ * DAC0 -> both PCM1792A (L+R, each in mono mode)
+ * ADC1 <- 1st PCM1804
+ * ADC2 <- 2nd PCM1804
+ * ADC3 <- 3rd PCM1804
+ */
+
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include "oxygen.h"
+
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_DESCRIPTION("Studio Evolution SE6X driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{Studio Evolution,SE6X}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "card index");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "enable card");
+
+static const struct pci_device_id se6x_ids[] = {
+ { OXYGEN_PCI_SUBID(0x13f6, 0x8788) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, se6x_ids);
+
+static void se6x_init(struct oxygen *chip)
+{
+ oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, 0x005);
+
+ snd_component_add(chip->card, "PCM1792A");
+ snd_component_add(chip->card, "PCM1804");
+}
+
+static int se6x_control_filter(struct snd_kcontrol_new *template)
+{
+ /* no DAC volume/mute */
+ if (!strncmp(template->name, "Master Playback ", 16))
+ return 1;
+ return 0;
+}
+
+static void se6x_cleanup(struct oxygen *chip)
+{
+}
+
+static void set_pcm1792a_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+ /* nothing to do (the microcontroller monitors DAC_LRCK) */
+}
+
+static void set_pcm1804_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
+{
+}
+
+static unsigned int se6x_adjust_dac_routing(struct oxygen *chip,
+ unsigned int play_routing)
+{
+ /* route the same stereo pair to DAC0 and DAC1 */
+ return ( play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+ ((play_routing << 2) & OXYGEN_PLAY_DAC1_SOURCE_MASK);
+}
+
+static const struct oxygen_model model_se6x = {
+ .shortname = "Studio Evolution SE6X",
+ .longname = "C-Media Oxygen HD Audio",
+ .chip = "CMI8787",
+ .init = se6x_init,
+ .control_filter = se6x_control_filter,
+ .cleanup = se6x_cleanup,
+ .set_dac_params = set_pcm1792a_params,
+ .set_adc_params = set_pcm1804_params,
+ .adjust_dac_routing = se6x_adjust_dac_routing,
+ .device_config = PLAYBACK_0_TO_I2S |
+ CAPTURE_0_FROM_I2S_1 |
+ CAPTURE_2_FROM_I2S_2 |
+ CAPTURE_3_FROM_I2S_3,
+ .dac_channels_pcm = 2,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 256, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_I2S,
+};
+
+static int se6x_get_model(struct oxygen *chip,
+ const struct pci_device_id *pci_id)
+{
+ chip->model = model_se6x;
+ return 0;
+}
+
+static int se6x_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ static int dev;
+ int err;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ ++dev;
+ return -ENOENT;
+ }
+ err = oxygen_pci_probe(pci, index[dev], id[dev], THIS_MODULE,
+ se6x_ids, se6x_get_model);
+ if (err >= 0)
+ ++dev;
+ return err;
+}
+
+static struct pci_driver se6x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = se6x_ids,
+ .probe = se6x_probe,
+ .remove = oxygen_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+ .driver = {
+ .pm = &oxygen_pci_pm,
+ },
+#endif
+ .shutdown = oxygen_pci_shutdown,
+};
+
+module_pci_driver(se6x_driver);
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index 181f7729d409..c5194f5b150a 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -24,7 +24,7 @@
#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include "pcxhr.h"
#include "pcxhr_mixer.h"
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 15a8ce5f1f48..80633055e17e 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -25,7 +25,7 @@
#include <linux/firmware.h>
#include <linux/pci.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/hwdep.h>
#include "pcxhr.h"
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 6abc2ac8fffb..94639d6b5fb5 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -99,7 +99,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -1153,7 +1153,6 @@ static void riptide_handleirq(unsigned long dev_id)
#ifdef CONFIG_PM_SLEEP
static int riptide_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_riptide *chip = card->private_data;
@@ -1161,27 +1160,14 @@ static int riptide_suspend(struct device *dev)
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int riptide_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_riptide *chip = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- printk(KERN_ERR "riptide: pci_enable_device failed, "
- "disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_riptide_initialize(chip);
snd_ac97_resume(chip->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -1706,14 +1692,11 @@ static struct snd_pcm_ops snd_riptide_capture_ops = {
.pointer = snd_riptide_pointer,
};
-static int
-snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
+static int snd_riptide_pcm(struct snd_riptide *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err =
snd_pcm_new(chip->card, "RIPTIDE", device, PLAYBACK_SUBSTREAMS, 1,
&pcm)) < 0)
@@ -1729,8 +1712,6 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
snd_dma_pci_data(chip->pci),
64 * 1024, 128 * 1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -2030,32 +2011,43 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
static int dev;
struct gameport *gameport;
+ int ret;
if (dev >= SNDRV_CARDS)
return -ENODEV;
+
if (!enable[dev]) {
- dev++;
- return -ENOENT;
+ ret = -ENOENT;
+ goto inc_dev;
}
- if (!joystick_port[dev++])
- return 0;
+ if (!joystick_port[dev]) {
+ ret = 0;
+ goto inc_dev;
+ }
gameport = gameport_allocate_port();
- if (!gameport)
- return -ENOMEM;
+ if (!gameport) {
+ ret = -ENOMEM;
+ goto inc_dev;
+ }
if (!request_region(joystick_port[dev], 8, "Riptide gameport")) {
snd_printk(KERN_WARNING
"Riptide: cannot grab gameport 0x%x\n",
joystick_port[dev]);
gameport_free_port(gameport);
- return -EBUSY;
+ ret = -EBUSY;
+ goto inc_dev;
}
gameport->io = joystick_port[dev];
gameport_register_port(gameport);
pci_set_drvdata(pci, gameport);
- return 0;
+
+ ret = 0;
+inc_dev:
+ dev++;
+ return ret;
}
static void snd_riptide_joystick_remove(struct pci_dev *pci)
@@ -2092,7 +2084,7 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (err < 0)
goto error;
card->private_data = chip;
- err = snd_riptide_pcm(chip, 0, NULL);
+ err = snd_riptide_pcm(chip, 0);
if (err < 0)
goto error;
err = snd_riptide_mixer(chip);
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 6c60dcd2e5a1..23d7f5d30c41 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -75,6 +75,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -85,8 +86,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
@@ -632,7 +631,7 @@ snd_rme32_setframelog(struct rme32 * rme32, int n_channels, int is_playback)
}
}
-static int snd_rme32_setformat(struct rme32 * rme32, int format)
+static int snd_rme32_setformat(struct rme32 *rme32, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 2f1a85185a16..2306ccf7281e 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -29,6 +29,7 @@
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -38,8 +39,6 @@
#include <sound/asoundef.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
/* note, two last pcis should be equal, it is not a bug */
MODULE_AUTHOR("Anders Torger <torger@ludd.luth.se>");
@@ -922,8 +921,7 @@ snd_rme96_setframelog(struct rme96 *rme96,
}
static int
-snd_rme96_playback_setformat(struct rme96 *rme96,
- int format)
+snd_rme96_playback_setformat(struct rme96 *rme96, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -940,8 +938,7 @@ snd_rme96_playback_setformat(struct rme96 *rme96,
}
static int
-snd_rme96_capture_setformat(struct rme96 *rme96,
- int format)
+snd_rme96_capture_setformat(struct rme96 *rme96, snd_pcm_format_t format)
{
switch (format) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -2358,7 +2355,6 @@ snd_rme96_create_switches(struct snd_card *card,
static int rme96_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
@@ -2381,26 +2377,14 @@ static int rme96_suspend(struct device *dev)
/* disable the DAC */
rme96->areg &= ~RME96_AR_DAC_EN;
writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG);
-
- pci_disable_device(pci);
- pci_save_state(pci);
-
return 0;
}
static int rme96_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct rme96 *rme96 = card->private_data;
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
-
/* reset playback and record buffer pointers */
writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS
+ rme96->playback_pointer);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index cf5a6c8b9a63..c19e021ccf66 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/math64.h>
#include <linux/vmalloc.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -42,7 +43,6 @@
#include <asm/byteorder.h>
#include <asm/current.h>
-#include <asm/io.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -1428,10 +1428,8 @@ static void snd_hdsp_midi_output_timer(unsigned long data)
leaving istimer wherever it was set before.
*/
- if (hmidi->istimer) {
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
- }
+ if (hmidi->istimer)
+ mod_timer(&hmidi->timer, 1 + jiffies);
spin_unlock_irqrestore (&hmidi->lock, flags);
}
@@ -1445,11 +1443,9 @@ static void snd_hdsp_midi_output_trigger(struct snd_rawmidi_substream *substream
spin_lock_irqsave (&hmidi->lock, flags);
if (up) {
if (!hmidi->istimer) {
- init_timer(&hmidi->timer);
- hmidi->timer.function = snd_hdsp_midi_output_timer;
- hmidi->timer.data = (unsigned long) hmidi;
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
+ setup_timer(&hmidi->timer, snd_hdsp_midi_output_timer,
+ (unsigned long) hmidi);
+ mod_timer(&hmidi->timer, 1 + jiffies);
hmidi->istimer++;
}
} else {
@@ -5309,9 +5305,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
release_firmware(hdsp->firmware);
vfree(hdsp->fw_uploaded);
-
- if (hdsp->iobase)
- iounmap(hdsp->iobase);
+ iounmap(hdsp->iobase);
if (hdsp->port)
pci_release_regions(hdsp->pci);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 3342705a5715..ca67f896d117 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -136,7 +136,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/math64.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -1957,10 +1957,8 @@ static void snd_hdspm_midi_output_timer(unsigned long data)
leaving istimer wherever it was set before.
*/
- if (hmidi->istimer) {
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
- }
+ if (hmidi->istimer)
+ mod_timer(&hmidi->timer, 1 + jiffies);
spin_unlock_irqrestore (&hmidi->lock, flags);
}
@@ -1975,11 +1973,9 @@ snd_hdspm_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
spin_lock_irqsave (&hmidi->lock, flags);
if (up) {
if (!hmidi->istimer) {
- init_timer(&hmidi->timer);
- hmidi->timer.function = snd_hdspm_midi_output_timer;
- hmidi->timer.data = (unsigned long) hmidi;
- hmidi->timer.expires = 1 + jiffies;
- add_timer(&hmidi->timer);
+ setup_timer(&hmidi->timer, snd_hdspm_midi_output_timer,
+ (unsigned long) hmidi);
+ mod_timer(&hmidi->timer, 1 + jiffies);
hmidi->istimer++;
}
} else {
@@ -6086,6 +6082,9 @@ static int snd_hdspm_playback_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
64, 8192);
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS,
+ 2, 2);
break;
}
@@ -6160,6 +6159,9 @@ static int snd_hdspm_capture_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
64, 8192);
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS,
+ 2, 2);
break;
}
@@ -6965,9 +6967,7 @@ static int snd_hdspm_free(struct hdspm * hdspm)
free_irq(hdspm->irq, (void *) hdspm);
kfree(hdspm->mixer);
-
- if (hdspm->iobase)
- iounmap(hdspm->iobase);
+ iounmap(hdspm->iobase);
if (hdspm->port)
pci_release_regions(hdspm->pci);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index 6521521853b8..fdbc0aa2776a 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -34,7 +35,6 @@
#include <sound/initval.h>
#include <asm/current.h>
-#include <asm/io.h>
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -1756,8 +1756,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652)
if (rme9652->irq >= 0)
free_irq(rme9652->irq, (void *)rme9652);
- if (rme9652->iobase)
- iounmap(rme9652->iobase);
+ iounmap(rme9652->iobase);
if (rme9652->port)
pci_release_regions(rme9652->pci);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 7f6a0a0d115a..efe669b80256 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1064,12 +1064,9 @@ static int sis_chip_free(struct sis7019 *sis)
if (sis->irq >= 0)
free_irq(sis->irq, sis);
- if (sis->ioaddr)
- iounmap(sis->ioaddr);
-
+ iounmap(sis->ioaddr);
pci_release_regions(sis->pci);
pci_disable_device(sis->pci);
-
sis_free_suspend(sis);
return 0;
}
@@ -1211,7 +1208,6 @@ static int sis_chip_init(struct sis7019 *sis)
#ifdef CONFIG_PM_SLEEP
static int sis_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct sis7019 *sis = card->private_data;
void __iomem *ioaddr = sis->ioaddr;
@@ -1240,9 +1236,6 @@ static int sis_suspend(struct device *dev)
ioaddr += 4096;
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
@@ -1254,14 +1247,6 @@ static int sis_resume(struct device *dev)
void __iomem *ioaddr = sis->ioaddr;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
-
- if (pci_enable_device(pci) < 0) {
- dev_err(&pci->dev, "unable to re-enable device\n");
- goto error;
- }
-
if (sis_chip_init(sis)) {
dev_err(&pci->dev, "unable to re-init controller\n");
goto error;
@@ -1284,7 +1269,6 @@ static int sis_resume(struct device *dev)
memset(sis->suspend_state[0], 0, 4096);
sis->irq = pci->irq;
- pci_set_master(pci);
if (sis->codecs_present & SIS_PRIMARY_CODEC_PRESENT)
snd_ac97_resume(sis->ac97[0]);
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 313a7328bf9c..0f40624a4275 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -30,6 +30,7 @@
#include <linux/gameport.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -39,8 +40,6 @@
#include <sound/opl3.h>
#include <sound/initval.h>
-#include <asm/io.h>
-
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("S3 SonicVibes PCI");
MODULE_LICENSE("GPL");
@@ -880,8 +879,7 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = {
.pointer = snd_sonicvibes_capture_pointer,
};
-static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
- struct snd_pcm **rpcm)
+static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device)
{
struct snd_pcm *pcm;
int err;
@@ -902,8 +900,6 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(sonic->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1491,7 +1487,7 @@ static int snd_sonic_probe(struct pci_dev *pci,
(unsigned long long)pci_resource_start(pci, 1),
sonic->irq);
- if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
+ if ((err = snd_sonicvibes_pcm(sonic, 0)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index a54cd6879b31..cedf13b64803 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -127,21 +127,21 @@ static int snd_trident_probe(struct pci_dev *pci,
sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d",
card->shortname, trident->port, trident->irq);
- if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
switch (trident->device) {
case TRIDENT_DEVICE_ID_DX:
case TRIDENT_DEVICE_ID_NX:
- if ((err = snd_trident_foldback_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_foldback_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
break;
}
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {
- if ((err = snd_trident_spdif_pcm(trident, pcm_dev++, NULL)) < 0) {
+ if ((err = snd_trident_spdif_pcm(trident, pcm_dev++)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h
index 5f110eb56e47..9624e5937719 100644
--- a/sound/pci/trident/trident.h
+++ b/sound/pci/trident/trident.h
@@ -420,9 +420,9 @@ int snd_trident_create(struct snd_card *card,
struct snd_trident ** rtrident);
int snd_trident_create_gameport(struct snd_trident *trident);
-int snd_trident_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_foldback_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
-int snd_trident_spdif_pcm(struct snd_trident * trident, int device, struct snd_pcm **rpcm);
+int snd_trident_pcm(struct snd_trident *trident, int device);
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device);
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device);
int snd_trident_attach_synthesizer(struct snd_trident * trident);
struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type,
int client, int port);
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 57cd757acfe7..b72be035f785 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -36,6 +36,7 @@
#include <linux/gameport.h>
#include <linux/dma-mapping.h>
#include <linux/export.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -44,8 +45,6 @@
#include "trident.h"
#include <sound/asoundef.h>
-#include <asm/io.h>
-
static int snd_trident_pcm_mixer_build(struct snd_trident *trident,
struct snd_trident_voice * voice,
struct snd_pcm_substream *substream);
@@ -2172,14 +2171,11 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = {
---------------------------------------------------------------------------*/
-int snd_trident_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm)) < 0)
return err;
@@ -2214,8 +2210,6 @@ int snd_trident_pcm(struct snd_trident *trident,
snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
}
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -2230,16 +2224,13 @@ int snd_trident_pcm(struct snd_trident *trident,
---------------------------------------------------------------------------*/
-int snd_trident_foldback_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_foldback_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *foldback;
int err;
int num_chan = 3;
struct snd_pcm_substream *substream;
- if (rpcm)
- *rpcm = NULL;
if (trident->device == TRIDENT_DEVICE_ID_NX)
num_chan = 4;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback)) < 0)
@@ -2271,8 +2262,6 @@ int snd_trident_foldback_pcm(struct snd_trident *trident,
snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = foldback;
return 0;
}
@@ -2287,14 +2276,11 @@ int snd_trident_foldback_pcm(struct snd_trident *trident,
---------------------------------------------------------------------------*/
-int snd_trident_spdif_pcm(struct snd_trident *trident,
- int device, struct snd_pcm **rpcm)
+int snd_trident_spdif_pcm(struct snd_trident *trident, int device)
{
struct snd_pcm *spdif;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif)) < 0)
return err;
@@ -2310,8 +2296,6 @@ int snd_trident_spdif_pcm(struct snd_trident *trident,
snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024);
- if (rpcm)
- *rpcm = spdif;
return 0;
}
@@ -3926,7 +3910,6 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
#ifdef CONFIG_PM_SLEEP
static int snd_trident_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_trident *trident = card->private_data;
@@ -3938,28 +3921,14 @@ static int snd_trident_suspend(struct device *dev)
snd_ac97_suspend(trident->ac97);
snd_ac97_suspend(trident->ac97_sec);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_trident_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_trident *trident = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
switch (trident->device) {
case TRIDENT_DEVICE_ID_DX:
snd_trident_4d_dx_init(trident);
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 04c474658e3c..b9ebb51893c5 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -23,7 +23,7 @@
*
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/mutex.h>
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index e088467fb736..8622283e89f3 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -46,7 +46,7 @@
* - Optimize position calculation for the 823x chips.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -2271,7 +2271,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
*/
static int snd_via82xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx *chip = card->private_data;
int i;
@@ -2291,28 +2290,15 @@ static int snd_via82xx_suspend(struct device *dev)
chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10);
}
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_via82xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_via82xx_chip_init(chip);
if (chip->chip_type == TYPE_VIA686) {
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index fd46ffe12e4f..99b9137bc677 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -31,7 +31,7 @@
* modems.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -1031,7 +1031,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
*/
static int snd_via82xx_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx_modem *chip = card->private_data;
int i;
@@ -1043,29 +1042,15 @@ static int snd_via82xx_suspend(struct device *dev)
snd_via82xx_channel_reset(chip, &chip->devs[i]);
synchronize_irq(chip->irq);
snd_ac97_suspend(chip->ac97);
-
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
static int snd_via82xx_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct via82xx_modem *chip = card->private_data;
int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
-
snd_via82xx_chip_init(chip);
snd_ac97_resume(chip->ac97);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index c5a25e39e3a8..ecbaf473fc1e 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -259,32 +259,17 @@ static void snd_vx222_remove(struct pci_dev *pci)
#ifdef CONFIG_PM_SLEEP
static int snd_vx222_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_vx222 *vx = card->private_data;
- int err;
- err = snd_vx_suspend(&vx->core);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
- return err;
+ return snd_vx_suspend(&vx->core);
}
static int snd_vx222_resume(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_vx222 *vx = card->private_data;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
return snd_vx_resume(&vx->core);
}
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 52c1a8d5b88a..af83b3b38052 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -24,11 +24,11 @@
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/tlv.h>
-#include <asm/io.h>
#include "vx222.h"
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 47a192369e8f..812e27a1bcbc 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -283,11 +283,11 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
card->shortname,
chip->reg_area_phys,
chip->irq);
- if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) {
+ if ((err = snd_ymfpci_pcm(chip, 0)) < 0) {
snd_card_free(card);
return err;
}
- if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) {
+ if ((err = snd_ymfpci_pcm_spdif(chip, 1)) < 0) {
snd_card_free(card);
return err;
}
@@ -297,12 +297,12 @@ static int snd_card_ymfpci_probe(struct pci_dev *pci,
return err;
}
if (chip->ac97->ext_id & AC97_EI_SDAC) {
- err = snd_ymfpci_pcm_4ch(chip, 2, NULL);
+ err = snd_ymfpci_pcm_4ch(chip, 2);
if (err < 0) {
snd_card_free(card);
return err;
}
- err = snd_ymfpci_pcm2(chip, 3, NULL);
+ err = snd_ymfpci_pcm2(chip, 3);
if (err < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h
index 4631a2348915..149d4cb46998 100644
--- a/sound/pci/ymfpci/ymfpci.h
+++ b/sound/pci/ymfpci/ymfpci.h
@@ -379,10 +379,10 @@ void snd_ymfpci_free_gameport(struct snd_ymfpci *chip);
extern const struct dev_pm_ops snd_ymfpci_pm;
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device);
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device);
int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 81c916a5eb96..4c26076dbf78 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -36,7 +37,6 @@
#include <sound/asoundef.h>
#include <sound/mpu401.h>
-#include <asm/io.h>
#include <asm/byteorder.h>
/*
@@ -1145,13 +1145,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = {
.pointer = snd_ymfpci_capture_pointer,
};
-int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm)) < 0)
return err;
pcm->private_data = chip;
@@ -1167,14 +1165,8 @@ int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_std_chmaps, 2, 0, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
@@ -1188,13 +1180,11 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = {
.pointer = snd_ymfpci_capture_pointer,
};
-int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
+int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0)
return err;
pcm->private_data = chip;
@@ -1210,8 +1200,6 @@ int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1226,14 +1214,11 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = {
.pointer = snd_ymfpci_playback_pointer,
};
-int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device,
- struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm)) < 0)
return err;
pcm->private_data = chip;
@@ -1248,8 +1233,6 @@ int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- if (rpcm)
- *rpcm = pcm;
return 0;
}
@@ -1272,14 +1255,11 @@ static const struct snd_pcm_chmap_elem surround_map[] = {
{ }
};
-int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device,
- struct snd_pcm **rpcm)
+int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device)
{
struct snd_pcm *pcm;
int err;
- if (rpcm)
- *rpcm = NULL;
if ((err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm)) < 0)
return err;
pcm->private_data = chip;
@@ -1294,14 +1274,8 @@ int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device,
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci), 64*1024, 256*1024);
- err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
surround_map, 2, 0, NULL);
- if (err < 0)
- return err;
-
- if (rpcm)
- *rpcm = pcm;
- return 0;
}
static int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -2272,8 +2246,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
release_and_free_resource(chip->mpu_res);
release_and_free_resource(chip->fm_res);
snd_ymfpci_free_gameport(chip);
- if (chip->reg_area_virt)
- iounmap(chip->reg_area_virt);
+ iounmap(chip->reg_area_virt);
if (chip->work_ptr.area)
snd_dma_free_pages(&chip->work_ptr);
@@ -2326,7 +2299,6 @@ static int saved_regs_index[] = {
static int snd_ymfpci_suspend(struct device *dev)
{
- struct pci_dev *pci = to_pci_dev(dev);
struct snd_card *card = dev_get_drvdata(dev);
struct snd_ymfpci *chip = card->private_data;
unsigned int i;
@@ -2347,9 +2319,6 @@ static int snd_ymfpci_suspend(struct device *dev)
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
snd_ymfpci_disable_dsp(chip);
- pci_disable_device(pci);
- pci_save_state(pci);
- pci_set_power_state(pci, PCI_D3hot);
return 0;
}
@@ -2360,14 +2329,6 @@ static int snd_ymfpci_resume(struct device *dev)
struct snd_ymfpci *chip = card->private_data;
unsigned int i;
- pci_set_power_state(pci, PCI_D0);
- pci_restore_state(pci);
- if (pci_enable_device(pci) < 0) {
- dev_err(dev, "pci_enable_device failed, disabling device\n");
- snd_card_disconnect(card);
- return -EIO;
- }
- pci_set_master(pci);
snd_ymfpci_aclink_reset(pci);
snd_ymfpci_codec_ready(chip, 0);
snd_ymfpci_download_image(chip);
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 5fbf5db2543d..09da7b52bc2e 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -20,7 +20,7 @@
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/nvram.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/sound/ppc/beep.c b/sound/ppc/beep.c
index 0040f048221f..d3524f9fa05d 100644
--- a/sound/ppc/beep.c
+++ b/sound/ppc/beep.c
@@ -18,7 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index cb4f0a5e984e..b86159e04493 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <sound/core.h>
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 5a13b22748b2..13146d701413 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -20,7 +20,7 @@
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -867,16 +867,11 @@ static int snd_pmac_free(struct snd_pmac *chip)
snd_pmac_dbdma_free(chip, &chip->capture.cmd);
snd_pmac_dbdma_free(chip, &chip->extra_dma);
snd_pmac_dbdma_free(chip, &emergency_dbdma);
- if (chip->macio_base)
- iounmap(chip->macio_base);
- if (chip->latch_base)
- iounmap(chip->latch_base);
- if (chip->awacs)
- iounmap(chip->awacs);
- if (chip->playback.dma)
- iounmap(chip->playback.dma);
- if (chip->capture.dma)
- iounmap(chip->capture.dma);
+ iounmap(chip->macio_base);
+ iounmap(chip->latch_base);
+ iounmap(chip->awacs);
+ iounmap(chip->playback.dma);
+ iounmap(chip->capture.dma);
if (chip->node) {
int i;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 58f292a87f98..368242519279 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -1044,7 +1044,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
if (!the_card.null_buffer_start_vaddr) {
pr_info("%s: nullbuffer alloc failed\n", __func__);
ret = -ENOMEM;
- goto clean_preallocate;
+ goto clean_card;
}
pr_debug("%s: null vaddr=%p dma=%#llx\n", __func__,
the_card.null_buffer_start_vaddr,
@@ -1066,8 +1066,6 @@ clean_dma_map:
PAGE_SIZE,
the_card.null_buffer_start_vaddr,
the_card.null_buffer_start_dma_addr);
-clean_preallocate:
- snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
clean_card:
snd_card_free(the_card.card);
clean_irq:
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 24c8766a925d..c8fafba218a5 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -32,8 +32,8 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/of_irq.h>
+#include <linux/io.h>
#include <sound/core.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index f44dda610ed2..ad3d9ae38034 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -35,12 +35,12 @@
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/info.h>
-#include <asm/io.h>
#include <asm/dma.h>
#include <mach/sysasic.h>
#include "aica.h"
@@ -343,11 +343,9 @@ static void spu_begin_dma(struct snd_pcm_substream *substream)
mod_timer(&dreamcastcard->timer, jiffies + 4);
return;
}
- init_timer(&(dreamcastcard->timer));
- dreamcastcard->timer.data = (unsigned long) substream;
- dreamcastcard->timer.function = aica_period_elapsed;
- dreamcastcard->timer.expires = jiffies + 4;
- add_timer(&(dreamcastcard->timer));
+ setup_timer(&dreamcastcard->timer, aica_period_elapsed,
+ (unsigned long) substream);
+ mod_timer(&dreamcastcard->timer, jiffies + 4);
}
static int snd_aicapcm_pcm_open(struct snd_pcm_substream
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index fb0b7e8b08ff..841d05946b88 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -187,6 +187,94 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * When the bit clock is input, limit the maximum rate according to the
+ * Serial Clock Ratio Considerations section from the SSC documentation:
+ *
+ * The Transmitter and the Receiver can be programmed to operate
+ * with the clock signals provided on either the TK or RK pins.
+ * This allows the SSC to support many slave-mode data transfers.
+ * In this case, the maximum clock speed allowed on the RK pin is:
+ * - Peripheral clock divided by 2 if Receiver Frame Synchro is input
+ * - Peripheral clock divided by 3 if Receiver Frame Synchro is output
+ * In addition, the maximum clock speed allowed on the TK pin is:
+ * - Peripheral clock divided by 6 if Transmit Frame Synchro is input
+ * - Peripheral clock divided by 2 if Transmit Frame Synchro is output
+ *
+ * When the bit clock is output, limit the rate according to the
+ * SSC divider restrictions.
+ */
+static int atmel_ssc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct atmel_ssc_info *ssc_p = rule->private;
+ struct ssc_device *ssc = ssc_p->ssc;
+ struct snd_interval *i = hw_param_interval(params, rule->var);
+ struct snd_interval t;
+ struct snd_ratnum r = {
+ .den_min = 1,
+ .den_max = 4095,
+ .den_step = 1,
+ };
+ unsigned int num = 0, den = 0;
+ int frame_size;
+ int mck_div = 2;
+ int ret;
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0)
+ return frame_size;
+
+ switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFS:
+ if ((ssc_p->dir_mask & SSC_DIR_MASK_CAPTURE)
+ && ssc->clk_from_rk_pin)
+ /* Receiver Frame Synchro (i.e. capture)
+ * is output (format is _CFS) and the RK pin
+ * is used for input (format is _CBM_).
+ */
+ mck_div = 3;
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ if ((ssc_p->dir_mask & SSC_DIR_MASK_PLAYBACK)
+ && !ssc->clk_from_rk_pin)
+ /* Transmit Frame Synchro (i.e. playback)
+ * is input (format is _CFM) and the TK pin
+ * is used for input (format _CBM_ but not
+ * using the RK pin).
+ */
+ mck_div = 6;
+ break;
+ }
+
+ switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ r.num = ssc_p->mck_rate / mck_div / frame_size;
+
+ ret = snd_interval_ratnum(i, 1, &r, &num, &den);
+ if (ret >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
+ params->rate_num = num;
+ params->rate_den = den;
+ }
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBM_CFM:
+ t.min = 8000;
+ t.max = ssc_p->mck_rate / mck_div / frame_size;
+ t.openmin = t.openmax = 0;
+ t.integer = 0;
+ ret = snd_interval_refine(i, &t);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
/*-------------------------------------------------------------------------*\
* DAI functions
@@ -200,6 +288,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
struct atmel_pcm_dma_params *dma_params;
int dir, dir_mask;
+ int ret;
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
ssc_readl(ssc_p->ssc->regs, SR));
@@ -207,6 +296,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
/* Enable PMC peripheral clock for this SSC */
pr_debug("atmel_ssc_dai: Starting clock\n");
clk_enable(ssc_p->ssc->clk);
+ ssc_p->mck_rate = clk_get_rate(ssc_p->ssc->clk);
/* Reset the SSC to keep it at a clean status */
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
@@ -219,6 +309,17 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
dir_mask = SSC_DIR_MASK_CAPTURE;
}
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ atmel_ssc_hw_rule_rate,
+ ssc_p,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (ret < 0) {
+ dev_err(dai->dev, "Failed to specify rate rule: %d\n", ret);
+ return ret;
+ }
+
dma_params = &ssc_dma_params[dai->id][dir];
dma_params->ssc = ssc_p->ssc;
dma_params->substream = substream;
@@ -783,8 +884,6 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
# define atmel_ssc_resume NULL
#endif /* CONFIG_PM */
-#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
-
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -804,12 +903,16 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
.playback = {
.channels_min = 1,
.channels_max = 2,
- .rates = ATMEL_SSC_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 384000,
.formats = ATMEL_SSC_FORMATS,},
.capture = {
.channels_min = 1,
.channels_max = 2,
- .rates = ATMEL_SSC_RATES,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 8000,
+ .rate_max = 384000,
.formats = ATMEL_SSC_FORMATS,},
.ops = &atmel_ssc_dai_ops,
};
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index b1f08d511495..80b153857a88 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -115,6 +115,7 @@ struct atmel_ssc_info {
unsigned short rcmr_period;
struct atmel_pcm_dma_params *dma_params[2];
struct atmel_ssc_state ssc_state;
+ unsigned long mck_rate;
};
int atmel_ssc_set_audio(int ssc_id);
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index f5ad214663f9..8de836165cf2 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -46,8 +46,6 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <asm/mach-types.h>
-
#include "../codecs/wm8731.h"
#include "atmel-pcm.h"
#include "atmel_ssc_dai.h"
@@ -171,9 +169,7 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
int ret;
if (!np) {
- if (!(machine_is_at91sam9g20ek() ||
- machine_is_at91sam9g20ek_2mmc()))
- return -ENODEV;
+ return -ENODEV;
}
ret = atmel_ssc_set_audio(0);
@@ -210,39 +206,37 @@ static int at91sam9g20ek_audio_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
/* Parse device node info */
- if (np) {
- ret = snd_soc_of_parse_card_name(card, "atmel,model");
- if (ret)
- goto err;
-
- ret = snd_soc_of_parse_audio_routing(card,
- "atmel,audio-routing");
- if (ret)
- goto err;
-
- /* Parse codec info */
- at91sam9g20ek_dai.codec_name = NULL;
- codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
- if (!codec_np) {
- dev_err(&pdev->dev, "codec info missing\n");
- return -EINVAL;
- }
- at91sam9g20ek_dai.codec_of_node = codec_np;
-
- /* Parse dai and platform info */
- at91sam9g20ek_dai.cpu_dai_name = NULL;
- at91sam9g20ek_dai.platform_name = NULL;
- cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
- if (!cpu_np) {
- dev_err(&pdev->dev, "dai and pcm info missing\n");
- return -EINVAL;
- }
- at91sam9g20ek_dai.cpu_of_node = cpu_np;
- at91sam9g20ek_dai.platform_of_node = cpu_np;
-
- of_node_put(codec_np);
- of_node_put(cpu_np);
+ ret = snd_soc_of_parse_card_name(card, "atmel,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "atmel,audio-routing");
+ if (ret)
+ goto err;
+
+ /* Parse codec info */
+ at91sam9g20ek_dai.codec_name = NULL;
+ codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+ if (!codec_np) {
+ dev_err(&pdev->dev, "codec info missing\n");
+ return -EINVAL;
+ }
+ at91sam9g20ek_dai.codec_of_node = codec_np;
+
+ /* Parse dai and platform info */
+ at91sam9g20ek_dai.cpu_dai_name = NULL;
+ at91sam9g20ek_dai.platform_name = NULL;
+ cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+ if (!cpu_np) {
+ dev_err(&pdev->dev, "dai and pcm info missing\n");
+ return -EINVAL;
}
+ at91sam9g20ek_dai.cpu_of_node = cpu_np;
+ at91sam9g20ek_dai.platform_of_node = cpu_np;
+
+ of_node_put(codec_np);
+ of_node_put(cpu_np);
ret = snd_soc_register_card(card);
if (ret) {
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index 7b7fbcd49e5e..c7cd60f009e9 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -16,7 +16,7 @@ config SND_EP93XX_SOC_AC97
config SND_EP93XX_SOC_SNAPPERCL15
tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
- depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+ depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C
select SND_EP93XX_SOC_I2S
select SND_SOC_TLV320AIC23_I2C
help
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 064e6c18e109..ea9f0e31f9d4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -69,7 +69,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98090 if I2C
select SND_SOC_MAX98095 if I2C
- select SND_SOC_MAX98357A
+ select SND_SOC_MAX98357A if GPIOLIB
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c
index 70ab35744aba..7ad8e156e2df 100644
--- a/sound/soc/codecs/adau1977.c
+++ b/sound/soc/codecs/adau1977.c
@@ -938,22 +938,15 @@ int adau1977_probe(struct device *dev, struct regmap *regmap,
adau1977->dvdd_reg = NULL;
}
- adau1977->reset_gpio = devm_gpiod_get(dev, "reset");
- if (IS_ERR(adau1977->reset_gpio)) {
- ret = PTR_ERR(adau1977->reset_gpio);
- if (ret != -ENOENT && ret != -ENOSYS)
- return PTR_ERR(adau1977->reset_gpio);
- adau1977->reset_gpio = NULL;
- }
+ adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(adau1977->reset_gpio))
+ return PTR_ERR(adau1977->reset_gpio);
dev_set_drvdata(dev, adau1977);
- if (adau1977->reset_gpio) {
- ret = gpiod_direction_output(adau1977->reset_gpio, 0);
- if (ret)
- return ret;
+ if (adau1977->reset_gpio)
ndelay(100);
- }
ret = adau1977_power_enable(adau1977);
if (ret)
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index f2b8aad21274..60598b230341 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -437,20 +437,13 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client,
}
/* Reset the Device */
- cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev,
- "reset-gpios");
- if (IS_ERR(cs35l32->reset_gpio)) {
- ret = PTR_ERR(cs35l32->reset_gpio);
- if (ret != -ENOENT && ret != -ENOSYS)
- return ret;
-
- cs35l32->reset_gpio = NULL;
- } else {
- ret = gpiod_direction_output(cs35l32->reset_gpio, 0);
- if (ret)
- return ret;
+ cs35l32->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs35l32->reset_gpio))
+ return PTR_ERR(cs35l32->reset_gpio);
+
+ if (cs35l32->reset_gpio)
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
- }
/* initialize codec */
ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, &reg);
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index ce6086835ebd..cac48ddf3ba6 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -605,21 +605,14 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
return ret;
}
- cs4265->reset_gpio = devm_gpiod_get(&i2c_client->dev,
- "reset-gpios");
- if (IS_ERR(cs4265->reset_gpio)) {
- ret = PTR_ERR(cs4265->reset_gpio);
- if (ret != -ENOENT && ret != -ENOSYS)
- return ret;
-
- cs4265->reset_gpio = NULL;
- } else {
- ret = gpiod_direction_output(cs4265->reset_gpio, 0);
- if (ret)
- return ret;
+ cs4265->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
+ "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(cs4265->reset_gpio))
+ return PTR_ERR(cs4265->reset_gpio);
+
+ if (cs4265->reset_gpio) {
mdelay(1);
gpiod_set_value_cansleep(cs4265->reset_gpio, 1);
-
}
i2c_set_clientdata(i2c_client, cs4265);
diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c
index 1806333ea29e..e9e6efbc21dd 100644
--- a/sound/soc/codecs/max98357a.c
+++ b/sound/soc/codecs/max98357a.c
@@ -12,9 +12,19 @@
* max98357a.c -- MAX98357A ALSA SoC Codec driver
*/
-#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
#define DRV_NAME "max98357a"
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 9974f201a08f..4b5f1fe9be97 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -54,6 +54,9 @@ struct pcm512x_priv {
int pll_d;
int pll_p;
unsigned long real_pll;
+ unsigned long overclock_pll;
+ unsigned long overclock_dac;
+ unsigned long overclock_dsp;
};
/*
@@ -224,6 +227,90 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
}
}
+static int pcm512x_overclock_pll_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = pcm512x->overclock_pll;
+ return 0;
+}
+
+static int pcm512x_overclock_pll_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ switch (codec->dapm.bias_level) {
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_STANDBY:
+ break;
+ default:
+ return -EBUSY;
+ }
+
+ pcm512x->overclock_pll = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int pcm512x_overclock_dsp_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = pcm512x->overclock_dsp;
+ return 0;
+}
+
+static int pcm512x_overclock_dsp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ switch (codec->dapm.bias_level) {
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_STANDBY:
+ break;
+ default:
+ return -EBUSY;
+ }
+
+ pcm512x->overclock_dsp = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int pcm512x_overclock_dac_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = pcm512x->overclock_dac;
+ return 0;
+}
+
+static int pcm512x_overclock_dac_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+ switch (codec->dapm.bias_level) {
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_STANDBY:
+ break;
+ default:
+ return -EBUSY;
+ }
+
+ pcm512x->overclock_dac = ucontrol->value.integer.value[0];
+ return 0;
+}
+
static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1);
static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
@@ -328,6 +415,13 @@ SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf),
SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus),
SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf),
SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds),
+
+SOC_SINGLE_EXT("Max Overclock PLL", SND_SOC_NOPM, 0, 20, 0,
+ pcm512x_overclock_pll_get, pcm512x_overclock_pll_put),
+SOC_SINGLE_EXT("Max Overclock DSP", SND_SOC_NOPM, 0, 40, 0,
+ pcm512x_overclock_dsp_get, pcm512x_overclock_dsp_put),
+SOC_SINGLE_EXT("Max Overclock DAC", SND_SOC_NOPM, 0, 40, 0,
+ pcm512x_overclock_dac_get, pcm512x_overclock_dac_put),
};
static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = {
@@ -346,6 +440,45 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
{ "OUTR", NULL, "DACR" },
};
+static unsigned long pcm512x_pll_max(struct pcm512x_priv *pcm512x)
+{
+ return 25000000 + 25000000 * pcm512x->overclock_pll / 100;
+}
+
+static unsigned long pcm512x_dsp_max(struct pcm512x_priv *pcm512x)
+{
+ return 50000000 + 50000000 * pcm512x->overclock_dsp / 100;
+}
+
+static unsigned long pcm512x_dac_max(struct pcm512x_priv *pcm512x,
+ unsigned long rate)
+{
+ return rate + rate * pcm512x->overclock_dac / 100;
+}
+
+static unsigned long pcm512x_sck_max(struct pcm512x_priv *pcm512x)
+{
+ if (!pcm512x->pll_out)
+ return 25000000;
+ return pcm512x_pll_max(pcm512x);
+}
+
+static unsigned long pcm512x_ncp_target(struct pcm512x_priv *pcm512x,
+ unsigned long dac_rate)
+{
+ /*
+ * If the DAC is not actually overclocked, use the good old
+ * NCP target rate...
+ */
+ if (dac_rate <= 6144000)
+ return 1536000;
+ /*
+ * ...but if the DAC is in fact overclocked, bump the NCP target
+ * rate to get the recommended dividers even when overclocking.
+ */
+ return pcm512x_dac_max(pcm512x, 1536000);
+}
+
static const u32 pcm512x_dai_rates[] = {
8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
88200, 96000, 176400, 192000, 384000,
@@ -359,6 +492,7 @@ static const struct snd_pcm_hw_constraint_list constraints_slave = {
static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
+ struct pcm512x_priv *pcm512x = rule->private;
struct snd_interval ranges[2];
int frame_size;
@@ -377,7 +511,7 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
*/
memset(ranges, 0, sizeof(ranges));
ranges[0].min = 8000;
- ranges[0].max = 25000000 / frame_size / 2;
+ ranges[0].max = pcm512x_sck_max(pcm512x) / frame_size / 2;
ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
ranges[1].max = 384000;
break;
@@ -408,7 +542,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
return snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
pcm512x_hw_rule_rate,
- NULL,
+ pcm512x,
SNDRV_PCM_HW_PARAM_FRAME_BITS,
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
@@ -517,6 +651,8 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
unsigned long bclk_rate)
{
struct device *dev = dai->dev;
+ struct snd_soc_codec *codec = dai->codec;
+ struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
unsigned long sck_rate;
int pow2;
@@ -527,9 +663,10 @@ static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
* as many factors of 2 as possible, as that makes it easier
* to find a fast DAC rate
*/
- pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+ pow2 = 1 << fls((pcm512x_pll_max(pcm512x) - 16000000) / bclk_rate);
for (; pow2; pow2 >>= 1) {
- sck_rate = rounddown(25000000, bclk_rate * pow2);
+ sck_rate = rounddown(pcm512x_pll_max(pcm512x),
+ bclk_rate * pow2);
if (sck_rate >= 16000000)
break;
}
@@ -678,7 +815,7 @@ static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
return 0; /* futile, quit early */
/* run DAC no faster than 6144000 Hz */
- for (dac_rate = rounddown(6144000, osr_rate);
+ for (dac_rate = rounddown(pcm512x_dac_max(pcm512x, 6144000), osr_rate);
dac_rate;
dac_rate -= osr_rate) {
@@ -805,7 +942,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
osr_rate = 16 * sample_rate;
/* run DSP no faster than 50 MHz */
- dsp_div = mck_rate > 50000000 ? 2 : 1;
+ dsp_div = mck_rate > pcm512x_dsp_max(pcm512x) ? 2 : 1;
dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
if (dac_rate) {
@@ -836,7 +973,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
dacsrc_rate = pllin_rate;
} else {
/* run DAC no faster than 6144000 Hz */
- unsigned long dac_mul = 6144000 / osr_rate;
+ unsigned long dac_mul = pcm512x_dac_max(pcm512x, 6144000)
+ / osr_rate;
unsigned long sck_mul = sck_rate / osr_rate;
for (; dac_mul; dac_mul--) {
@@ -863,28 +1001,30 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
dacsrc_rate = sck_rate;
}
+ osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+ if (osr_div > 128) {
+ dev_err(dev, "Failed to find OSR divider\n");
+ return -EINVAL;
+ }
+
dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
if (dac_div > 128) {
dev_err(dev, "Failed to find DAC divider\n");
return -EINVAL;
}
+ dac_rate = dacsrc_rate / dac_div;
- ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
- if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+ ncp_div = DIV_ROUND_CLOSEST(dac_rate,
+ pcm512x_ncp_target(pcm512x, dac_rate));
+ if (ncp_div > 128 || dac_rate / ncp_div > 2048000) {
/* run NCP no faster than 2048000 Hz, but why? */
- ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+ ncp_div = DIV_ROUND_UP(dac_rate, 2048000);
if (ncp_div > 128) {
dev_err(dev, "Failed to find NCP divider\n");
return -EINVAL;
}
}
- osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
- if (osr_div > 128) {
- dev_err(dev, "Failed to find OSR divider\n");
- return -EINVAL;
- }
-
idac = mck_rate / (dsp_div * sample_rate);
ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
@@ -937,11 +1077,11 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
return ret;
}
- if (sample_rate <= 48000)
+ if (sample_rate <= pcm512x_dac_max(pcm512x, 48000))
fssp = PCM512x_FSSP_48KHZ;
- else if (sample_rate <= 96000)
+ else if (sample_rate <= pcm512x_dac_max(pcm512x, 96000))
fssp = PCM512x_FSSP_96KHZ;
- else if (sample_rate <= 192000)
+ else if (sample_rate <= pcm512x_dac_max(pcm512x, 192000))
fssp = PCM512x_FSSP_192KHZ;
else
fssp = PCM512x_FSSP_384KHZ;
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index e1a4a45c57e2..fd102613d20d 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -225,7 +225,6 @@ static bool rt5670_volatile_register(struct device *dev, unsigned int reg)
case RT5670_ADC_EQ_CTRL1:
case RT5670_EQ_CTRL1:
case RT5670_ALC_CTRL_1:
- case RT5670_IRQ_CTRL1:
case RT5670_IRQ_CTRL2:
case RT5670_INT_IRQ_ST:
case RT5670_IL_CMD:
@@ -2703,6 +2702,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
regmap_write(rt5670->regmap, RT5670_RESET, 0);
+ regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val);
+ if (val >= 4)
+ regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980);
+ else
+ regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00);
+
ret = regmap_register_patch(rt5670->regmap, init_list,
ARRAY_SIZE(init_list));
if (ret != 0)
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 5d0bb8748dd1..fb9c20eace3f 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -3284,8 +3284,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IB45 Bypass Mux", "Bypass", "IB45 Mux" },
{ "IB45 Bypass Mux", "Pass SRC", "IB45 Mux" },
- { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6" },
- { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6" },
+ { "IB6 Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+ { "IB6 Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
{ "IB6 Mux", "SLB DAC 6", "SLB DAC6" },
{ "IB6 Mux", "STO4 ADC MIX L", "Stereo4 ADC MIXL" },
{ "IB6 Mux", "IF4 DAC L", "IF4 DAC L" },
@@ -3293,8 +3293,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IB6 Mux", "STO2 ADC MIX L", "Stereo2 ADC MIXL" },
{ "IB6 Mux", "STO3 ADC MIX L", "Stereo3 ADC MIXL" },
- { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7" },
- { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7" },
+ { "IB7 Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+ { "IB7 Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
{ "IB7 Mux", "SLB DAC 7", "SLB DAC7" },
{ "IB7 Mux", "STO4 ADC MIX R", "Stereo4 ADC MIXR" },
{ "IB7 Mux", "IF4 DAC R", "IF4 DAC R" },
@@ -3635,15 +3635,15 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "DAC1 FS", NULL, "DAC1 MIXL" },
{ "DAC1 FS", NULL, "DAC1 MIXR" },
- { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2" },
- { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2" },
+ { "DAC2 L Mux", "IF1 DAC 2", "IF1 DAC2 Mux" },
+ { "DAC2 L Mux", "IF2 DAC 2", "IF2 DAC2 Mux" },
{ "DAC2 L Mux", "IF3 DAC L", "IF3 DAC L" },
{ "DAC2 L Mux", "IF4 DAC L", "IF4 DAC L" },
{ "DAC2 L Mux", "SLB DAC 2", "SLB DAC2" },
{ "DAC2 L Mux", "OB 2", "OutBound2" },
- { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3" },
- { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3" },
+ { "DAC2 R Mux", "IF1 DAC 3", "IF1 DAC3 Mux" },
+ { "DAC2 R Mux", "IF2 DAC 3", "IF2 DAC3 Mux" },
{ "DAC2 R Mux", "IF3 DAC R", "IF3 DAC R" },
{ "DAC2 R Mux", "IF4 DAC R", "IF4 DAC R" },
{ "DAC2 R Mux", "SLB DAC 3", "SLB DAC3" },
@@ -3651,29 +3651,29 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "DAC2 R Mux", "Haptic Generator", "Haptic Generator" },
{ "DAC2 R Mux", "VAD ADC", "VAD ADC Mux" },
- { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4" },
- { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4" },
+ { "DAC3 L Mux", "IF1 DAC 4", "IF1 DAC4 Mux" },
+ { "DAC3 L Mux", "IF2 DAC 4", "IF2 DAC4 Mux" },
{ "DAC3 L Mux", "IF3 DAC L", "IF3 DAC L" },
{ "DAC3 L Mux", "IF4 DAC L", "IF4 DAC L" },
{ "DAC3 L Mux", "SLB DAC 4", "SLB DAC4" },
{ "DAC3 L Mux", "OB 4", "OutBound4" },
- { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC4" },
- { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC4" },
+ { "DAC3 R Mux", "IF1 DAC 5", "IF1 DAC5 Mux" },
+ { "DAC3 R Mux", "IF2 DAC 5", "IF2 DAC5 Mux" },
{ "DAC3 R Mux", "IF3 DAC R", "IF3 DAC R" },
{ "DAC3 R Mux", "IF4 DAC R", "IF4 DAC R" },
{ "DAC3 R Mux", "SLB DAC 5", "SLB DAC5" },
{ "DAC3 R Mux", "OB 5", "OutBound5" },
- { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6" },
- { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6" },
+ { "DAC4 L Mux", "IF1 DAC 6", "IF1 DAC6 Mux" },
+ { "DAC4 L Mux", "IF2 DAC 6", "IF2 DAC6 Mux" },
{ "DAC4 L Mux", "IF3 DAC L", "IF3 DAC L" },
{ "DAC4 L Mux", "IF4 DAC L", "IF4 DAC L" },
{ "DAC4 L Mux", "SLB DAC 6", "SLB DAC6" },
{ "DAC4 L Mux", "OB 6", "OutBound6" },
- { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7" },
- { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7" },
+ { "DAC4 R Mux", "IF1 DAC 7", "IF1 DAC7 Mux" },
+ { "DAC4 R Mux", "IF2 DAC 7", "IF2 DAC7 Mux" },
{ "DAC4 R Mux", "IF3 DAC R", "IF3 DAC R" },
{ "DAC4 R Mux", "IF4 DAC R", "IF4 DAC R" },
{ "DAC4 R Mux", "SLB DAC 7", "SLB DAC7" },
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 3a1343fa109b..007a0e3bc273 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -106,13 +106,11 @@ static const struct reg_default sta32x_regs[] = {
};
static const struct regmap_range sta32x_write_regs_range[] = {
- regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
- regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
+ regmap_reg_range(STA32X_CONFA, STA32X_FDRC2),
};
static const struct regmap_range sta32x_read_regs_range[] = {
- regmap_reg_range(STA32X_CONFA, STA32X_AUTO2),
- regmap_reg_range(STA32X_C1CFG, STA32X_FDRC2),
+ regmap_reg_range(STA32X_CONFA, STA32X_FDRC2),
};
static const struct regmap_range sta32x_volatile_regs_range[] = {
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index bda2ee18769e..669e3228241e 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -1213,27 +1213,15 @@ static int sta350_i2c_probe(struct i2c_client *i2c,
#endif
/* GPIOs */
- sta350->gpiod_nreset = devm_gpiod_get(dev, "reset");
- if (IS_ERR(sta350->gpiod_nreset)) {
- ret = PTR_ERR(sta350->gpiod_nreset);
- if (ret != -ENOENT && ret != -ENOSYS)
- return ret;
-
- sta350->gpiod_nreset = NULL;
- } else {
- gpiod_direction_output(sta350->gpiod_nreset, 0);
- }
-
- sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down");
- if (IS_ERR(sta350->gpiod_power_down)) {
- ret = PTR_ERR(sta350->gpiod_power_down);
- if (ret != -ENOENT && ret != -ENOSYS)
- return ret;
-
- sta350->gpiod_power_down = NULL;
- } else {
- gpiod_direction_output(sta350->gpiod_power_down, 0);
- }
+ sta350->gpiod_nreset = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(sta350->gpiod_nreset))
+ return PTR_ERR(sta350->gpiod_nreset);
+
+ sta350->gpiod_power_down = devm_gpiod_get(dev, "power-down",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(sta350->gpiod_power_down))
+ return PTR_ERR(sta350->gpiod_power_down);
/* regulators */
for (i = 0; i < ARRAY_SIZE(sta350->supplies); i++)
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index ae23acdd2708..dfb4ff5cc9ea 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -485,16 +485,9 @@ static int tas2552_probe(struct i2c_client *client,
if (data == NULL)
return -ENOMEM;
- data->enable_gpio = devm_gpiod_get(dev, "enable");
- if (IS_ERR(data->enable_gpio)) {
- ret = PTR_ERR(data->enable_gpio);
- if (ret != -ENOENT && ret != -ENOSYS)
- return ret;
-
- data->enable_gpio = NULL;
- } else {
- gpiod_direction_output(data->enable_gpio, 0);
- }
+ data->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(data->enable_gpio))
+ return PTR_ERR(data->enable_gpio);
data->tas2552_client = client;
data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config);
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 3f6959c8e2f7..de438871040b 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -512,6 +512,12 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
memcpy(priv->dai_link, fsl_asoc_card_dai,
sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link));
+ ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+ goto asrc_fail;
+ }
+
/* Normal DAI Link */
priv->dai_link[0].cpu_of_node = cpu_np;
priv->dai_link[0].codec_of_node = codec_np;
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2595611e8a6d..b9fabbf69db6 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -603,10 +603,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
factor = (div2 + 1) * (7 * psr + 1) * 2;
for (i = 0; i < 255; i++) {
- /* The bclk rate must be smaller than 1/5 sysclk rate */
- if (factor * (i + 1) < 5)
- continue;
-
tmprate = freq * factor * (i + 2);
if (baudclk_is_used)
@@ -614,6 +610,13 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream,
else
clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
+ /*
+ * Hardware limitation: The bclk rate must be
+ * never greater than 1/5 IPG clock rate
+ */
+ if (clkrate * 5 > clk_get_rate(ssi_private->clk))
+ continue;
+
clkrate /= factor;
afreq = clkrate / (i + 1);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index f7c6734bd5da..fb550b5869d2 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -372,6 +372,11 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
strlen(dai_link->cpu_dai_name) +
strlen(dai_link->codec_dai_name) + 2,
GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto dai_link_of_err;
+ }
+
sprintf(name, "%s-%s", dai_link->cpu_dai_name,
dai_link->codec_dai_name);
dai_link->name = dai_link->stream_name = name;
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c
index 9cf7d01479ad..fba2ef5dac42 100644
--- a/sound/soc/intel/broadwell.c
+++ b/sound/soc/intel/broadwell.c
@@ -110,9 +110,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP0 to 16 bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S16_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c
index 59308629043e..3b262d01c1b3 100644
--- a/sound/soc/intel/bytcr_dpcm_rt5640.c
+++ b/sound/soc/intel/bytcr_dpcm_rt5640.c
@@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP2 to 24-bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S24_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c
index bd29617a9ab9..dd935255a020 100644
--- a/sound/soc/intel/cht_bsw_rt5645.c
+++ b/sound/soc/intel/cht_bsw_rt5645.c
@@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP2 to 24-bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S24_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
index ff016621583a..bc8dcacd5e6a 100644
--- a/sound/soc/intel/cht_bsw_rt5672.c
+++ b/sound/soc/intel/cht_bsw_rt5672.c
@@ -178,9 +178,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP2 to 24-bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S24_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
@@ -217,7 +215,7 @@ static struct snd_soc_dai_link cht_dailink[] = {
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.platform_name = "sst-mfld-platform",
- .ignore_suspend = 1,
+ .nonatomic = true,
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
@@ -240,13 +238,13 @@ static struct snd_soc_dai_link cht_dailink[] = {
.cpu_dai_name = "ssp2-port",
.platform_name = "sst-mfld-platform",
.no_pcm = 1,
+ .nonatomic = true,
.codec_dai_name = "rt5670-aif1",
.codec_name = "i2c-10EC5670:00",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
| SND_SOC_DAIFMT_CBS_CFS,
.init = cht_codec_init,
.be_hw_params_fixup = cht_codec_fixup,
- .ignore_suspend = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
.ops = &cht_be_ssp2_ops,
@@ -285,7 +283,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
static struct platform_driver snd_cht_mc_driver = {
.driver = {
.name = "cht-bsw-rt5672",
- .pm = &snd_soc_pm_ops,
},
.probe = snd_cht_mc_probe,
};
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
index 35edf51a52aa..00fddd3f5dfb 100644
--- a/sound/soc/intel/haswell.c
+++ b/sound/soc/intel/haswell.c
@@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP0 to 16 bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S16_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h
index dfebfdd5eb2a..daecc58f28af 100644
--- a/sound/soc/intel/sst-atom-controls.h
+++ b/sound/soc/intel/sst-atom-controls.h
@@ -150,7 +150,7 @@ enum sst_cmd_type {
enum sst_task {
SST_TASK_SBA = 1,
- SST_TASK_MMX,
+ SST_TASK_MMX = 3,
};
enum sst_type {
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index 0ab1309ef274..394af5684c05 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -31,6 +31,7 @@
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
+#include <sound/asound.h>
#include "sst-haswell-ipc.h"
#include "sst-dsp.h"
@@ -242,6 +243,9 @@ struct sst_hsw_stream {
u32 (*notify_position)(struct sst_hsw_stream *stream, void *data);
void *pdata;
+ /* record the fw read position when playback */
+ snd_pcm_uframes_t old_position;
+ bool play_silence;
struct list_head node;
};
@@ -1347,6 +1351,30 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
return 0;
}
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->old_position;
+}
+
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, snd_pcm_uframes_t val)
+{
+ stream->old_position = val;
+}
+
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream)
+{
+ return stream->play_silence;
+}
+
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, bool val)
+{
+ stream->play_silence = val;
+}
+
/* Stream Information - these calls could be inline but we want the IPC
ABI to be opaque to client PCM drivers to cope with any future ABI changes */
int sst_hsw_mixer_get_info(struct sst_hsw *hsw)
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index c1ad901342f2..858096041cb1 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <sound/asound.h>
#define SST_HSW_NO_CHANNELS 4
#define SST_HSW_MAX_DX_REGIONS 14
@@ -425,6 +426,14 @@ int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size);
int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size);
+snd_pcm_uframes_t sst_hsw_stream_get_old_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+void sst_hsw_stream_set_old_position(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, snd_pcm_uframes_t val);
+bool sst_hsw_stream_get_silence_start(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream);
+void sst_hsw_stream_set_silence_start(struct sst_hsw *hsw,
+ struct sst_hsw_stream *stream, bool val);
int sst_hsw_mixer_get_info(struct sst_hsw *hsw);
/* Stream ALSA trigger operations */
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 78fa01be57f2..7e21e8f85885 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -36,6 +36,11 @@
#define HSW_PCM_COUNT 6
#define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */
+#define SST_OLD_POSITION(d, r, o) ((d) + \
+ frames_to_bytes(r, o))
+#define SST_SAMPLES(r, x) (bytes_to_samples(r, \
+ frames_to_bytes(r, (x))))
+
/* simple volume table */
static const u32 volume_map[] = {
HSW_VOLUME_MAX >> 30,
@@ -86,7 +91,8 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_DRAIN_TRIGGER,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = PAGE_SIZE,
@@ -577,23 +583,34 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct hsw_priv_data *pdata =
snd_soc_platform_get_drvdata(rtd->platform);
struct hsw_pcm_data *pcm_data;
+ struct sst_hsw_stream *sst_stream;
struct sst_hsw *hsw = pdata->hsw;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t pos;
int dai;
dai = mod_map[rtd->cpu_dai->id].dai_id;
pcm_data = &pdata->pcm[dai][substream->stream];
+ sst_stream = pcm_data->stream;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ sst_hsw_stream_set_silence_start(hsw, sst_stream, false);
sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
break;
+ case SNDRV_PCM_TRIGGER_DRAIN:
+ pos = runtime->control->appl_ptr % runtime->buffer_size;
+ sst_hsw_stream_set_old_position(hsw, pcm_data->stream, pos);
+ sst_hsw_stream_set_silence_start(hsw, sst_stream, true);
+ break;
default:
break;
}
@@ -607,13 +624,62 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
struct snd_pcm_substream *substream = pcm_data->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+ struct sst_hsw *hsw = pdata->hsw;
u32 pos;
+ snd_pcm_uframes_t position = bytes_to_frames(runtime,
+ sst_hsw_get_dsp_position(hsw, pcm_data->stream));
+ unsigned char *dma_area = runtime->dma_area;
+ snd_pcm_uframes_t dma_frames =
+ bytes_to_frames(runtime, runtime->dma_bytes);
+ snd_pcm_uframes_t old_position;
+ ssize_t samples;
pos = frames_to_bytes(runtime,
(runtime->control->appl_ptr % runtime->buffer_size));
dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+ /* SST fw don't know where to stop dma
+ * So, SST driver need to clean the data which has been consumed
+ */
+ if (dma_area == NULL || dma_frames <= 0
+ || (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ || !sst_hsw_stream_get_silence_start(hsw, stream)) {
+ snd_pcm_period_elapsed(substream);
+ return pos;
+ }
+
+ old_position = sst_hsw_stream_get_old_position(hsw, stream);
+ if (position > old_position) {
+ if (position < dma_frames) {
+ samples = SST_SAMPLES(runtime, position - old_position);
+ snd_pcm_format_set_silence(runtime->format,
+ SST_OLD_POSITION(dma_area,
+ runtime, old_position),
+ samples);
+ } else
+ dev_err(rtd->dev, "PCM: position is wrong\n");
+ } else {
+ if (old_position < dma_frames) {
+ samples = SST_SAMPLES(runtime,
+ dma_frames - old_position);
+ snd_pcm_format_set_silence(runtime->format,
+ SST_OLD_POSITION(dma_area,
+ runtime, old_position),
+ samples);
+ } else
+ dev_err(rtd->dev, "PCM: dma_bytes is wrong\n");
+ if (position < dma_frames) {
+ samples = SST_SAMPLES(runtime, position);
+ snd_pcm_format_set_silence(runtime->format,
+ dma_area, samples);
+ } else
+ dev_err(rtd->dev, "PCM: position is wrong\n");
+ }
+ sst_hsw_stream_set_old_position(hsw, stream, position);
+
/* let alsa know we have play a period */
snd_pcm_period_elapsed(substream);
return pos;
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index 7523cbef8780..2fbaf2c75d17 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
ret_val = stream->ops->stream_drop(sst->dev, str_id);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
dev_dbg(rtd->dev, "sst: in pause\n");
status = SST_PLATFORM_PAUSED;
ret_val = stream->ops->stream_pause(sst->dev, str_id);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
dev_dbg(rtd->dev, "sst: in pause release\n");
status = SST_PLATFORM_RUNNING;
ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
@@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
static int sst_soc_probe(struct snd_soc_platform *platform)
{
+ struct sst_data *drv = dev_get_drvdata(platform->dev);
+
+ drv->soc_card = platform->component.card;
return sst_dsp_init_v2_dpcm(platform);
}
@@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+
+static int sst_soc_prepare(struct device *dev)
+{
+ struct sst_data *drv = dev_get_drvdata(dev);
+ int i;
+
+ /* suspend all pcms first */
+ snd_soc_suspend(drv->soc_card->dev);
+ snd_soc_poweroff(drv->soc_card->dev);
+
+ /* set the SSPs to idle */
+ for (i = 0; i < drv->soc_card->num_rtd; i++) {
+ struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+ if (dai->active) {
+ send_ssp_cmd(dai, dai->name, 0);
+ sst_handle_vb_timer(dai, false);
+ }
+ }
+
+ return 0;
+}
+
+static void sst_soc_complete(struct device *dev)
+{
+ struct sst_data *drv = dev_get_drvdata(dev);
+ int i;
+
+ /* restart SSPs */
+ for (i = 0; i < drv->soc_card->num_rtd; i++) {
+ struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai;
+
+ if (dai->active) {
+ sst_handle_vb_timer(dai, true);
+ send_ssp_cmd(dai, dai->name, 1);
+ }
+ }
+ snd_soc_resume(drv->soc_card->dev);
+}
+
+#else
+
+#define sst_soc_prepare NULL
+#define sst_soc_complete NULL
+
+#endif
+
+
+static const struct dev_pm_ops sst_platform_pm = {
+ .prepare = sst_soc_prepare,
+ .complete = sst_soc_complete,
+};
+
static struct platform_driver sst_platform_driver = {
.driver = {
.name = "sst-mfld-platform",
+ .pm = &sst_platform_pm,
},
.probe = sst_platform_probe,
.remove = sst_platform_remove,
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 79c8d1246a8f..9094314be2b0 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -174,6 +174,7 @@ struct sst_data {
struct sst_platform_data *pdata;
struct snd_sst_bytes_v2 *byte_stream;
struct mutex lock;
+ struct snd_soc_card *soc_card;
};
int sst_register_dsp(struct sst_device *sst);
int sst_unregister_dsp(struct sst_device *sst);
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c
index 8a8d56a146e7..1a7eeec444b1 100644
--- a/sound/soc/intel/sst/sst.c
+++ b/sound/soc/intel/sst/sst.c
@@ -350,7 +350,9 @@ static inline void sst_save_shim64(struct intel_sst_drv *ctx,
spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
- shim_regs->imrx = sst_shim_read64(shim, SST_IMRX),
+ shim_regs->imrx = sst_shim_read64(shim, SST_IMRX);
+ shim_regs->csr = sst_shim_read64(shim, SST_CSR);
+
spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
}
@@ -367,6 +369,7 @@ static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
*/
spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
+ sst_shim_write64(shim, SST_CSR, shim_regs->csr),
spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
}
@@ -379,6 +382,10 @@ void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
* initially active. So change the state to active before
* enabling the pm
*/
+
+ if (!acpi_disabled)
+ pm_runtime_set_active(ctx->dev);
+
pm_runtime_enable(ctx->dev);
if (acpi_disabled)
@@ -409,29 +416,142 @@ static int intel_sst_runtime_suspend(struct device *dev)
synchronize_irq(ctx->irq_num);
flush_workqueue(ctx->post_msg_wq);
+ ctx->ops->reset(ctx);
/* save the shim registers because PMC doesn't save state */
sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
return ret;
}
-static int intel_sst_runtime_resume(struct device *dev)
+static int intel_sst_suspend(struct device *dev)
{
- int ret = 0;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+ struct sst_fw_save *fw_save;
+ int i, ret = 0;
- if (ctx->sst_state == SST_RESET) {
- ret = sst_load_fw(ctx);
- if (ret) {
- dev_err(dev, "FW download fail %d\n", ret);
- sst_set_fw_state_locked(ctx, SST_RESET);
+ /* check first if we are already in SW reset */
+ if (ctx->sst_state == SST_RESET)
+ return 0;
+
+ /*
+ * check if any stream is active and running
+ * they should already by suspend by soc_suspend
+ */
+ for (i = 1; i <= ctx->info.max_streams; i++) {
+ struct stream_info *stream = &ctx->streams[i];
+
+ if (stream->status == STREAM_RUNNING) {
+ dev_err(dev, "stream %d is running, cant susupend, abort\n", i);
+ return -EBUSY;
}
}
+ synchronize_irq(ctx->irq_num);
+ flush_workqueue(ctx->post_msg_wq);
+
+ /* Move the SST state to Reset */
+ sst_set_fw_state_locked(ctx, SST_RESET);
+
+ /* tell DSP we are suspending */
+ if (ctx->ops->save_dsp_context(ctx))
+ return -EBUSY;
+
+ /* save the memories */
+ fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL);
+ if (!fw_save)
+ return -ENOMEM;
+ fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL);
+ if (!fw_save->iram) {
+ ret = -ENOMEM;
+ goto iram;
+ }
+ fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL);
+ if (!fw_save->dram) {
+ ret = -ENOMEM;
+ goto dram;
+ }
+ fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL);
+ if (!fw_save->sram) {
+ ret = -ENOMEM;
+ goto sram;
+ }
+
+ fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL);
+ if (!fw_save->ddr) {
+ ret = -ENOMEM;
+ goto ddr;
+ }
+
+ memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base);
+ memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base);
+ memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE);
+ memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base);
+
+ ctx->fw_save = fw_save;
+ ctx->ops->reset(ctx);
+ return 0;
+ddr:
+ kfree(fw_save->sram);
+sram:
+ kfree(fw_save->dram);
+dram:
+ kfree(fw_save->iram);
+iram:
+ kfree(fw_save);
+ return ret;
+}
+
+static int intel_sst_resume(struct device *dev)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+ struct sst_fw_save *fw_save = ctx->fw_save;
+ int ret = 0;
+ struct sst_block *block;
+
+ if (!fw_save)
+ return 0;
+
+ sst_set_fw_state_locked(ctx, SST_FW_LOADING);
+
+ /* we have to restore the memory saved */
+ ctx->ops->reset(ctx);
+
+ ctx->fw_save = NULL;
+
+ memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base);
+ memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base);
+ memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE);
+ memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base);
+
+ kfree(fw_save->sram);
+ kfree(fw_save->dram);
+ kfree(fw_save->iram);
+ kfree(fw_save->ddr);
+ kfree(fw_save);
+
+ block = sst_create_block(ctx, 0, FW_DWNL_ID);
+ if (block == NULL)
+ return -ENOMEM;
+
+
+ /* start and wait for ack */
+ ctx->ops->start(ctx);
+ ret = sst_wait_timeout(ctx, block);
+ if (ret) {
+ dev_err(ctx->dev, "fw download failed %d\n", ret);
+ /* FW download failed due to timeout */
+ ret = -EBUSY;
+
+ } else {
+ sst_set_fw_state_locked(ctx, SST_FW_RUNNING);
+ }
+
+ sst_free_block(ctx, block);
return ret;
}
const struct dev_pm_ops intel_sst_pm = {
+ .suspend = intel_sst_suspend,
+ .resume = intel_sst_resume,
.runtime_suspend = intel_sst_runtime_suspend,
- .runtime_resume = intel_sst_runtime_resume,
};
EXPORT_SYMBOL_GPL(intel_sst_pm);
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h
index 562bc483d6b7..3f493862e98d 100644
--- a/sound/soc/intel/sst/sst.h
+++ b/sound/soc/intel/sst/sst.h
@@ -337,6 +337,13 @@ struct sst_shim_regs64 {
u64 csr2;
};
+struct sst_fw_save {
+ void *iram;
+ void *dram;
+ void *sram;
+ void *ddr;
+};
+
/**
* struct intel_sst_drv - driver ops
*
@@ -428,6 +435,8 @@ struct intel_sst_drv {
* persistent till worker thread gets called
*/
char firmware_name[FW_NAME_SIZE];
+
+ struct sst_fw_save *fw_save;
};
/* misc definitions */
@@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx,
int sst_context_init(struct intel_sst_drv *ctx);
void sst_context_cleanup(struct intel_sst_drv *ctx);
void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
+void memcpy32_toio(void __iomem *dst, const void *src, int count);
+void memcpy32_fromio(void *dst, const void __iomem *src, int count);
+
#endif
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c
index 5f75ef3cdd22..f0e4b99b3aeb 100644
--- a/sound/soc/intel/sst/sst_drv_interface.c
+++ b/sound/soc/intel/sst/sst_drv_interface.c
@@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx,
static int sst_power_control(struct device *dev, bool state)
{
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
-
- dev_dbg(ctx->dev, "state:%d", state);
- if (state == true)
- return pm_runtime_get_sync(dev);
- else
+ int ret = 0;
+ int usage_count = 0;
+
+#ifdef CONFIG_PM
+ usage_count = atomic_read(&dev->power.usage_count);
+#else
+ usage_count = 1;
+#endif
+
+ if (state == true) {
+ ret = pm_runtime_get_sync(dev);
+
+ dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret);
+ return ret;
+ }
+ if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) {
+ ret = sst_load_fw(ctx);
+ if (ret) {
+ dev_err(dev, "FW download fail %d\n", ret);
+ sst_set_fw_state_locked(ctx, SST_RESET);
+ ret = sst_pm_runtime_put(ctx);
+ }
+ }
+ } else {
+ dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count);
return sst_pm_runtime_put(ctx);
+ }
+ return ret;
}
/*
@@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id)
return sst_drop_stream(ctx, str_id);
}
+static int sst_stream_pause(struct device *dev, int str_id)
+{
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state != SST_FW_RUNNING)
+ return 0;
+
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+
+ return sst_pause_stream(ctx, str_id);
+}
+
+static int sst_stream_resume(struct device *dev, int str_id)
+{
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state != SST_FW_RUNNING)
+ return 0;
+
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ return sst_resume_stream(ctx, str_id);
+}
+
static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
{
int str_id = 0;
@@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = {
.stream_init = sst_stream_init,
.stream_start = sst_stream_start,
.stream_drop = sst_stream_drop,
+ .stream_pause = sst_stream_pause,
+ .stream_pause_release = sst_stream_resume,
.stream_read_tstamp = sst_read_timestamp,
.send_byte_stream = sst_send_byte_stream,
.close = sst_close_pcm_stream,
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c
index 7888cd707853..e88907ae8b15 100644
--- a/sound/soc/intel/sst/sst_loader.c
+++ b/sound/soc/intel/sst/sst_loader.c
@@ -39,7 +39,15 @@
#include "sst.h"
#include "../sst-dsp.h"
-static inline void memcpy32_toio(void __iomem *dst, const void *src, int count)
+void memcpy32_toio(void __iomem *dst, const void *src, int count)
+{
+ /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+ * right count in words
+ */
+ __iowrite32_copy(dst, src, count/4);
+}
+
+void memcpy32_fromio(void *dst, const void __iomem *src, int count)
{
/* __iowrite32_copy uses 32-bit count values so divide by 4 for
* right count in words
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
index ccfb41c22e53..f7eb42aa3f38 100644
--- a/sound/soc/omap/omap-hdmi-audio.c
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -352,6 +352,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
return ret;
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
card->name = devm_kasprintf(dev, GFP_KERNEL,
"HDMI %s", dev_name(ad->dssdev));
card->owner = THIS_MODULE;
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index c7eb9dd67f60..fd99d89de6a8 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -530,8 +530,19 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
case OMAP_MCBSP_SYSCLK_CLKX_EXT:
regs->srgr2 |= CLKSM;
+ regs->pcr0 |= SCLKME;
+ /*
+ * If McBSP is master but yet the CLKX/CLKR pin drives the SRG,
+ * disable output on those pins. This enables to inject the
+ * reference clock through CLKX/CLKR. For this to work
+ * set_dai_sysclk() _needs_ to be called after set_dai_fmt().
+ */
+ regs->pcr0 &= ~CLKXM;
+ break;
case OMAP_MCBSP_SYSCLK_CLKR_EXT:
regs->pcr0 |= SCLKME;
+ /* Disable ouput on CLKR pin in master mode */
+ regs->pcr0 &= ~CLKRM;
break;
default:
err = -ENODEV;
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index f4b05bc23e4b..1343ecbf0bd5 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -201,7 +201,7 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
int ret;
- ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64));
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 3cebf6ca03df..0632a36852c8 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -174,7 +174,7 @@ config SND_SOC_SMDK_WM8994_PCM
config SND_SOC_SPEYSIDE
tristate "Audio support for Wolfson Speyside"
- depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+ depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C && SPI_MASTER
select SND_SAMSUNG_I2S
select SND_SOC_WM8996
select SND_SOC_WM9081
@@ -189,7 +189,7 @@ config SND_SOC_TOBERMORY
config SND_SOC_BELLS
tristate "Audio support for Wolfson Bells"
- depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
+ depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA && I2C && SPI_MASTER
select SND_SAMSUNG_I2S
select SND_SOC_WM5102
select SND_SOC_WM5110
@@ -206,7 +206,7 @@ config SND_SOC_LOWLAND
config SND_SOC_LITTLEMILL
tristate "Audio support for Wolfson Littlemill"
- depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+ depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && I2C
select SND_SAMSUNG_I2S
select MFD_WM8994
select SND_SOC_WM8994
@@ -223,7 +223,7 @@ config SND_SOC_SNOW
config SND_SOC_ODROIDX2
tristate "Audio support for Odroid-X2 and Odroid-U3"
- depends on SND_SOC_SAMSUNG
+ depends on SND_SOC_SAMSUNG && I2C
select SND_SOC_MAX98090
select SND_SAMSUNG_I2S
help
@@ -231,6 +231,6 @@ config SND_SOC_ODROIDX2
config SND_SOC_ARNDALE_RT5631_ALC5631
tristate "Audio support for RT5631(ALC5631) on Arndale Board"
- depends on SND_SOC_SAMSUNG
+ depends on SND_SOC_SAMSUNG && I2C
select SND_SAMSUNG_I2S
select SND_SOC_RT5631
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 1b53605f7154..110577c52317 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1252,6 +1252,8 @@ static int rsnd_probe(struct platform_device *pdev)
goto exit_snd_probe;
}
+ dev_set_drvdata(dev, priv);
+
/*
* asoc register
*/
@@ -1268,8 +1270,6 @@ static int rsnd_probe(struct platform_device *pdev)
goto exit_snd_soc;
}
- dev_set_drvdata(dev, priv);
-
pm_runtime_enable(dev);
dev_info(dev, "probed\n");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 30579ca5bacb..5c0658d49609 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1561,6 +1561,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
card->num_dapm_widgets);
+ if (card->of_dapm_widgets)
+ snd_soc_dapm_new_controls(&card->dapm, card->of_dapm_widgets,
+ card->num_of_dapm_widgets);
+
/* initialise the sound card only once */
if (card->probe) {
ret = card->probe(card);
@@ -1616,6 +1620,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
+ if (card->of_dapm_routes)
+ snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
+ card->num_of_dapm_routes);
+
for (i = 0; i < card->num_links; i++) {
if (card->dai_link[i].dai_fmt)
snd_soc_runtime_set_dai_fmt(&card->rtd[i],
@@ -3223,8 +3231,8 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
widgets[i].name = wname;
}
- card->dapm_widgets = widgets;
- card->num_dapm_widgets = num_widgets;
+ card->of_dapm_widgets = widgets;
+ card->num_of_dapm_widgets = num_widgets;
return 0;
}
@@ -3308,8 +3316,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
}
}
- card->num_dapm_routes = num_routes;
- card->dapm_routes = routes;
+ card->num_of_dapm_routes = num_routes;
+ card->of_dapm_routes = routes;
return 0;
}
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 4864392bfcba..c9917ca5de1a 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -151,7 +151,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
hw.info |= SNDRV_PCM_INFO_BATCH;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- addr_widths = dma_caps.dstn_addr_widths;
+ addr_widths = dma_caps.dst_addr_widths;
else
addr_widths = dma_caps.src_addr_widths;
}
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 0ae0e2a9eed7..6e3781e88f9a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -301,34 +301,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
return symmetry;
}
-/*
- * List of sample sizes that might go over the bus for parameter
- * application. There ought to be a wildcard sample size for things
- * like the DAC/ADC resolution to use but there isn't right now.
- */
-static int sample_sizes[] = {
- 24, 32,
-};
-
static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- int ret, i;
+ int ret;
if (!bits)
return;
- for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) {
- if (bits >= sample_sizes[i])
- continue;
-
- ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0,
- sample_sizes[i], bits);
- if (ret != 0)
- dev_warn(rtd->dev,
- "ASoC: Failed to set MSB %d/%d: %d\n",
- bits, sample_sizes[i], ret);
- }
+ ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
+ if (ret != 0)
+ dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d\n",
+ bits, ret);
}
static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
@@ -2527,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
/* DAPM dai link stream work */
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
+ pcm->nonatomic = rtd->dai_link->nonatomic;
rtd->pcm = pcm;
pcm->private_data = rtd;
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index 86280d63b76d..1b1a89e80d13 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -37,6 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -44,7 +45,6 @@
#include <sound/control.h>
#include <sound/initval.h>
-#include <asm/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index 93522072bc87..49195325fdf6 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -53,9 +53,7 @@ int snd_emux_new(struct snd_emux **remu)
emu->max_voices = 0;
emu->use_time = 0;
- init_timer(&emu->tlist);
- emu->tlist.function = snd_emux_timer_callback;
- emu->tlist.data = (unsigned long)emu;
+ setup_timer(&emu->tlist, snd_emux_timer_callback, (unsigned long)emu);
emu->timer_active = 0;
*remu = emu;
@@ -160,12 +158,8 @@ int snd_emux_free(struct snd_emux *emu)
snd_emux_detach_seq_oss(emu);
#endif
snd_emux_detach_seq(emu);
-
snd_emux_delete_hwdep(emu);
-
- if (emu->sflist)
- snd_sf_free(emu->sflist);
-
+ snd_sf_free(emu->sflist);
kfree(emu->voices);
kfree(emu->name);
kfree(emu);
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index 5ae1eae9f6db..e557946718a9 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -21,7 +21,7 @@
#include <sound/core.h>
#include <sound/hwdep.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "emux_voice.h"
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index 319754cf6208..ab37add269ae 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -26,7 +26,7 @@
#ifdef CONFIG_SND_SEQUENCER_OSS
#include <linux/export.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <sound/core.h>
#include "emux_voice.h"
#include <sound/asoundef.h>
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index 9a38de459acb..599551b5af44 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -186,8 +186,7 @@ snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
*/
vp->state = SNDRV_EMUX_ST_PENDING;
if (! emu->timer_active) {
- emu->tlist.expires = jiffies + 1;
- add_timer(&emu->tlist);
+ mod_timer(&emu->tlist, jiffies + 1);
emu->timer_active = 1;
}
} else
@@ -223,8 +222,7 @@ void snd_emux_timer_callback(unsigned long data)
}
}
if (do_again) {
- emu->tlist.expires = jiffies + 1;
- add_timer(&emu->tlist);
+ mod_timer(&emu->tlist, jiffies + 1);
emu->timer_active = 1;
} else
emu->timer_active = 0;
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 78683b2064f7..31a4ea94830e 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -25,7 +25,7 @@
* of doing things so that the old sfxload utility can be used.
* Everything may change when there is an alsa way of doing things.
*/
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <sound/core.h>
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index d393153c474f..a452ad7cec40 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -160,5 +160,7 @@ config SND_BCD2000
To compile this driver as a module, choose M here: the module
will be called snd-bcd2000.
+source "sound/usb/line6/Kconfig"
+
endif # SND_USB
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index bcee4060fd18..2d2d122b069f 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
+obj-$(CONFIG_SND_USB_LINE6) += line6/
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 97acb906acc2..ef580b43f1e3 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -153,6 +153,8 @@ struct snd_usb_substream {
int channel;
int byte_idx;
} dsd_dop;
+
+ bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
};
struct snd_usb_stream {
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 03fed6611d9e..2ed260b10f6d 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -303,6 +303,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
return err;
}
+ /* Don't check the sample rate for devices which we know don't
+ * support reading */
+ if (snd_usb_get_sample_rate_quirk(chip))
+ return 0;
+
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig
new file mode 100644
index 000000000000..f4585d378ef3
--- /dev/null
+++ b/sound/usb/line6/Kconfig
@@ -0,0 +1,42 @@
+config SND_USB_LINE6
+ tristate
+ select SND_RAWMIDI
+ select SND_PCM
+
+config SND_USB_POD
+ tristate "Line 6 POD USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for PODxt and other similar devices,
+ supporting the following features:
+ * Reading/writing individual parameters
+ * Reading/writing complete channel, effects setup, and amp
+ setup data
+ * Channel switching
+ * Virtual MIDI interface
+ * Tuner access
+ * Playback/capture/mixer device for any ALSA-compatible PCM
+ audio application
+ * Signal routing (record clean/processed guitar signal,
+ re-amping)
+
+config SND_USB_PODHD
+ tristate "Line 6 POD HD300/400/500 USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for POD HD300, 400 and 500 devices.
+
+config SND_USB_TONEPORT
+ tristate "TonePort GX, UX1 and UX2 USB support"
+ select SND_USB_LINE6
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This is a driver for TonePort GX, UX1 and UX2 devices.
+
+config SND_USB_VARIAX
+ tristate "Variax Workbench USB support"
+ select SND_USB_LINE6
+ help
+ This is a driver for Variax Workbench device.
+
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile
new file mode 100644
index 000000000000..b8b3b2a543d8
--- /dev/null
+++ b/sound/usb/line6/Makefile
@@ -0,0 +1,18 @@
+snd-usb-line6-y := \
+ capture.o \
+ driver.o \
+ midi.o \
+ midibuf.o \
+ pcm.o \
+ playback.o
+
+snd-usb-pod-y := pod.o
+snd-usb-podhd-y := podhd.o
+snd-usb-toneport-y := toneport.o
+snd-usb-variax-y := variax.o
+
+obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o
+obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o
+obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o
+obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o
+obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c
new file mode 100644
index 000000000000..f518fbbe88de
--- /dev/null
+++ b/sound/usb/line6/capture.c
@@ -0,0 +1,275 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "pcm.h"
+
+/*
+ Find a free URB and submit it.
+ must be called in line6pcm->in.lock context
+*/
+static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
+{
+ int index;
+ int i, urb_size;
+ int ret;
+ struct urb *urb_in;
+
+ index =
+ find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS);
+
+ if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+ return -EINVAL;
+ }
+
+ urb_in = line6pcm->in.urbs[index];
+ urb_size = 0;
+
+ for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+ struct usb_iso_packet_descriptor *fin =
+ &urb_in->iso_frame_desc[i];
+ fin->offset = urb_size;
+ fin->length = line6pcm->max_packet_size;
+ urb_size += line6pcm->max_packet_size;
+ }
+
+ urb_in->transfer_buffer =
+ line6pcm->in.buffer +
+ index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+ urb_in->transfer_buffer_length = urb_size;
+ urb_in->context = line6pcm;
+
+ ret = usb_submit_urb(urb_in, GFP_ATOMIC);
+
+ if (ret == 0)
+ set_bit(index, &line6pcm->in.active_urbs);
+ else
+ dev_err(line6pcm->line6->ifcdev,
+ "URB in #%d submission failed (%d)\n", index, ret);
+
+ return 0;
+}
+
+/*
+ Submit all currently available capture URBs.
+ must be called in line6pcm->in.lock context
+*/
+int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ ret = submit_audio_in_urb(line6pcm);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ Copy data into ALSA capture buffer.
+*/
+void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
+{
+ struct snd_pcm_substream *substream =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+ int frames = fsize / bytes_per_frame;
+
+ if (runtime == NULL)
+ return;
+
+ if (line6pcm->in.pos_done + frames > runtime->buffer_size) {
+ /*
+ The transferred area goes over buffer boundary,
+ copy two separate chunks.
+ */
+ int len;
+
+ len = runtime->buffer_size - line6pcm->in.pos_done;
+
+ if (len > 0) {
+ memcpy(runtime->dma_area +
+ line6pcm->in.pos_done * bytes_per_frame, fbuf,
+ len * bytes_per_frame);
+ memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
+ (frames - len) * bytes_per_frame);
+ } else {
+ /* this is somewhat paranoid */
+ dev_err(line6pcm->line6->ifcdev,
+ "driver bug: len = %d\n", len);
+ }
+ } else {
+ /* copy single chunk */
+ memcpy(runtime->dma_area +
+ line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize);
+ }
+
+ line6pcm->in.pos_done += frames;
+ if (line6pcm->in.pos_done >= runtime->buffer_size)
+ line6pcm->in.pos_done -= runtime->buffer_size;
+}
+
+void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
+{
+ struct snd_pcm_substream *substream =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+
+ line6pcm->in.bytes += length;
+ if (line6pcm->in.bytes >= line6pcm->in.period) {
+ line6pcm->in.bytes %= line6pcm->in.period;
+ spin_unlock(&line6pcm->in.lock);
+ snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->in.lock);
+ }
+}
+
+/*
+ * Callback for completed capture URB.
+ */
+static void audio_in_callback(struct urb *urb)
+{
+ int i, index, length = 0, shutdown = 0;
+ unsigned long flags;
+
+ struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+
+ line6pcm->in.last_frame = urb->start_frame;
+
+ /* find index of URB */
+ for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
+ if (urb == line6pcm->in.urbs[index])
+ break;
+
+ spin_lock_irqsave(&line6pcm->in.lock, flags);
+
+ for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+ char *fbuf;
+ int fsize;
+ struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
+
+ if (fin->status == -EXDEV) {
+ shutdown = 1;
+ break;
+ }
+
+ fbuf = urb->transfer_buffer + fin->offset;
+ fsize = fin->actual_length;
+
+ if (fsize > line6pcm->max_packet_size) {
+ dev_err(line6pcm->line6->ifcdev,
+ "driver and/or device bug: packet too large (%d > %d)\n",
+ fsize, line6pcm->max_packet_size);
+ }
+
+ length += fsize;
+
+ /* the following assumes LINE6_ISO_PACKETS == 1: */
+ line6pcm->prev_fbuf = fbuf;
+ line6pcm->prev_fsize = fsize;
+
+ if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+ test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) &&
+ fsize > 0)
+ line6_capture_copy(line6pcm, fbuf, fsize);
+ }
+
+ clear_bit(index, &line6pcm->in.active_urbs);
+
+ if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs))
+ shutdown = 1;
+
+ if (!shutdown) {
+ submit_audio_in_urb(line6pcm);
+
+ if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) &&
+ test_bit(LINE6_STREAM_PCM, &line6pcm->in.running))
+ line6_capture_check_period(line6pcm, length);
+ }
+
+ spin_unlock_irqrestore(&line6pcm->in.lock, flags);
+}
+
+/* open capture callback */
+static int snd_line6_capture_open(struct snd_pcm_substream *substream)
+{
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+ err = snd_pcm_hw_constraint_ratdens(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &line6pcm->properties->rates);
+ if (err < 0)
+ return err;
+
+ runtime->hw = line6pcm->properties->capture_hw;
+ return 0;
+}
+
+/* close capture callback */
+static int snd_line6_capture_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/* capture operators */
+struct snd_pcm_ops snd_line6_capture_ops = {
+ .open = snd_line6_capture_open,
+ .close = snd_line6_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_line6_hw_params,
+ .hw_free = snd_line6_hw_free,
+ .prepare = snd_line6_prepare,
+ .trigger = snd_line6_trigger,
+ .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+ struct usb_line6 *line6 = line6pcm->line6;
+ int i;
+
+ /* create audio URBs and fill in constant values: */
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ struct urb *urb;
+
+ /* URB for audio in: */
+ urb = line6pcm->in.urbs[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ urb->dev = line6->usbdev;
+ urb->pipe =
+ usb_rcvisocpipe(line6->usbdev,
+ line6->properties->ep_audio_r &
+ USB_ENDPOINT_NUMBER_MASK);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->start_frame = -1;
+ urb->number_of_packets = LINE6_ISO_PACKETS;
+ urb->interval = LINE6_ISO_INTERVAL;
+ urb->error_count = 0;
+ urb->complete = audio_in_callback;
+ }
+
+ return 0;
+}
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h
new file mode 100644
index 000000000000..890b21bff18c
--- /dev/null
+++ b/sound/usb/line6/capture.h
@@ -0,0 +1,29 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef CAPTURE_H
+#define CAPTURE_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+extern struct snd_pcm_ops snd_line6_capture_ops;
+
+extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
+ int fsize);
+extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
+ int length);
+extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
new file mode 100644
index 000000000000..81b7da8e56d3
--- /dev/null
+++ b/sound/usb/line6/driver.c
@@ -0,0 +1,672 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "midi.h"
+#include "playback.h"
+
+#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>"
+#define DRIVER_DESC "Line 6 USB Driver"
+
+/*
+ This is Line 6's MIDI manufacturer ID.
+*/
+const unsigned char line6_midi_id[] = {
+ 0x00, 0x01, 0x0c
+};
+EXPORT_SYMBOL_GPL(line6_midi_id);
+
+/*
+ Code to request version of POD, Variax interface
+ (and maybe other devices).
+*/
+static const char line6_request_version[] = {
+ 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
+};
+
+/*
+ Class for asynchronous messages.
+*/
+struct message {
+ struct usb_line6 *line6;
+ const char *buffer;
+ int size;
+ int done;
+};
+
+/*
+ Forward declarations.
+*/
+static void line6_data_received(struct urb *urb);
+static int line6_send_raw_message_async_part(struct message *msg,
+ struct urb *urb);
+
+/*
+ Start to listen on endpoint.
+*/
+static int line6_start_listen(struct usb_line6 *line6)
+{
+ int err;
+
+ usb_fill_int_urb(line6->urb_listen, line6->usbdev,
+ usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+ line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+ line6_data_received, line6, line6->interval);
+ line6->urb_listen->actual_length = 0;
+ err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
+ return err;
+}
+
+/*
+ Stop listening on endpoint.
+*/
+static void line6_stop_listen(struct usb_line6 *line6)
+{
+ usb_kill_urb(line6->urb_listen);
+}
+
+/*
+ Send raw message in pieces of wMaxPacketSize bytes.
+*/
+static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ int i, done = 0;
+
+ for (i = 0; i < size; i += line6->max_packet_size) {
+ int partial;
+ const char *frag_buf = buffer + i;
+ int frag_size = min(line6->max_packet_size, size - i);
+ int retval;
+
+ retval = usb_interrupt_msg(line6->usbdev,
+ usb_sndintpipe(line6->usbdev,
+ line6->properties->ep_ctrl_w),
+ (char *)frag_buf, frag_size,
+ &partial, LINE6_TIMEOUT * HZ);
+
+ if (retval) {
+ dev_err(line6->ifcdev,
+ "usb_interrupt_msg failed (%d)\n", retval);
+ break;
+ }
+
+ done += frag_size;
+ }
+
+ return done;
+}
+
+/*
+ Notification of completion of asynchronous request transmission.
+*/
+static void line6_async_request_sent(struct urb *urb)
+{
+ struct message *msg = (struct message *)urb->context;
+
+ if (msg->done >= msg->size) {
+ usb_free_urb(urb);
+ kfree(msg);
+ } else
+ line6_send_raw_message_async_part(msg, urb);
+}
+
+/*
+ Asynchronously send part of a raw message.
+*/
+static int line6_send_raw_message_async_part(struct message *msg,
+ struct urb *urb)
+{
+ int retval;
+ struct usb_line6 *line6 = msg->line6;
+ int done = msg->done;
+ int bytes = min(msg->size - done, line6->max_packet_size);
+
+ usb_fill_int_urb(urb, line6->usbdev,
+ usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+ (char *)msg->buffer + done, bytes,
+ line6_async_request_sent, msg, line6->interval);
+
+ msg->done += bytes;
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval < 0) {
+ dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
+ __func__, retval);
+ usb_free_urb(urb);
+ kfree(msg);
+ return retval;
+ }
+
+ return 0;
+}
+
+/*
+ Setup and start timer.
+*/
+void line6_start_timer(struct timer_list *timer, unsigned long msecs,
+ void (*function)(unsigned long), unsigned long data)
+{
+ setup_timer(timer, function, data);
+ mod_timer(timer, jiffies + msecs_to_jiffies(msecs));
+}
+EXPORT_SYMBOL_GPL(line6_start_timer);
+
+/*
+ Asynchronously send raw message.
+*/
+int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ struct message *msg;
+ struct urb *urb;
+
+ /* create message: */
+ msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ /* create URB: */
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (urb == NULL) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ /* set message data: */
+ msg->line6 = line6;
+ msg->buffer = buffer;
+ msg->size = size;
+ msg->done = 0;
+
+ /* start sending: */
+ return line6_send_raw_message_async_part(msg, urb);
+}
+EXPORT_SYMBOL_GPL(line6_send_raw_message_async);
+
+/*
+ Send asynchronous device version request.
+*/
+int line6_version_request_async(struct usb_line6 *line6)
+{
+ char *buffer;
+ int retval;
+
+ buffer = kmemdup(line6_request_version,
+ sizeof(line6_request_version), GFP_ATOMIC);
+ if (buffer == NULL)
+ return -ENOMEM;
+
+ retval = line6_send_raw_message_async(line6, buffer,
+ sizeof(line6_request_version));
+ kfree(buffer);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(line6_version_request_async);
+
+/*
+ Send sysex message in pieces of wMaxPacketSize bytes.
+*/
+int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
+ int size)
+{
+ return line6_send_raw_message(line6, buffer,
+ size + SYSEX_EXTRA_SIZE) -
+ SYSEX_EXTRA_SIZE;
+}
+EXPORT_SYMBOL_GPL(line6_send_sysex_message);
+
+/*
+ Allocate buffer for sysex message and prepare header.
+ @param code sysex message code
+ @param size number of bytes between code and sysex end
+*/
+char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
+ int size)
+{
+ char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
+
+ if (!buffer)
+ return NULL;
+
+ buffer[0] = LINE6_SYSEX_BEGIN;
+ memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
+ buffer[sizeof(line6_midi_id) + 1] = code1;
+ buffer[sizeof(line6_midi_id) + 2] = code2;
+ buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
+ return buffer;
+}
+EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer);
+
+/*
+ Notification of data received from the Line 6 device.
+*/
+static void line6_data_received(struct urb *urb)
+{
+ struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+ struct midi_buffer *mb = &line6->line6midi->midibuf_in;
+ int done;
+
+ if (urb->status == -ESHUTDOWN)
+ return;
+
+ done =
+ line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+
+ if (done < urb->actual_length) {
+ line6_midibuf_ignore(mb, done);
+ dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
+ done, urb->actual_length);
+ }
+
+ for (;;) {
+ done =
+ line6_midibuf_read(mb, line6->buffer_message,
+ LINE6_MESSAGE_MAXLEN);
+
+ if (done == 0)
+ break;
+
+ line6->message_length = done;
+ line6_midi_receive(line6, line6->buffer_message, done);
+
+ if (line6->process_message)
+ line6->process_message(line6);
+ }
+
+ line6_start_listen(line6);
+}
+
+#define LINE6_READ_WRITE_STATUS_DELAY 2 /* milliseconds */
+#define LINE6_READ_WRITE_MAX_RETRIES 50
+
+/*
+ Read data from device.
+*/
+int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
+ unsigned datalen)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ int ret;
+ unsigned char len;
+ unsigned count;
+
+ if (address > 0xffff || datalen > 0xff)
+ return -EINVAL;
+
+ /* query the serial number: */
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ (datalen << 8) | 0x21, address,
+ NULL, 0, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
+ return ret;
+ }
+
+ /* Wait for data length. We'll get 0xff until length arrives. */
+ for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
+ mdelay(LINE6_READ_WRITE_STATUS_DELAY);
+
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ 0x0012, 0x0000, &len, 1,
+ LINE6_TIMEOUT * HZ);
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "receive length failed (error %d)\n", ret);
+ return ret;
+ }
+
+ if (len != 0xff)
+ break;
+ }
+
+ if (len == 0xff) {
+ dev_err(line6->ifcdev, "read failed after %d retries\n",
+ count);
+ return -EIO;
+ } else if (len != datalen) {
+ /* should be equal or something went wrong */
+ dev_err(line6->ifcdev,
+ "length mismatch (expected %d, got %d)\n",
+ (int)datalen, (int)len);
+ return -EIO;
+ }
+
+ /* receive the result: */
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x0013, 0x0000, data, datalen,
+ LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_read_data);
+
+/*
+ Write data to device.
+*/
+int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
+ unsigned datalen)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ int ret;
+ unsigned char status;
+ int count;
+
+ if (address > 0xffff || datalen > 0xffff)
+ return -EINVAL;
+
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x0022, address, data, datalen,
+ LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "write request failed (error %d)\n", ret);
+ return ret;
+ }
+
+ for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
+ mdelay(LINE6_READ_WRITE_STATUS_DELAY);
+
+ ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+ 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+ USB_DIR_IN,
+ 0x0012, 0x0000,
+ &status, 1, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(line6->ifcdev,
+ "receiving status failed (error %d)\n", ret);
+ return ret;
+ }
+
+ if (status != 0xff)
+ break;
+ }
+
+ if (status == 0xff) {
+ dev_err(line6->ifcdev, "write failed after %d retries\n",
+ count);
+ return -EIO;
+ } else if (status != 0) {
+ dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_write_data);
+
+/*
+ Read Line 6 device serial number.
+ (POD, TonePort, GuitarPort)
+*/
+int line6_read_serial_number(struct usb_line6 *line6, u32 *serial_number)
+{
+ return line6_read_data(line6, 0x80d0, serial_number,
+ sizeof(*serial_number));
+}
+EXPORT_SYMBOL_GPL(line6_read_serial_number);
+
+/*
+ Card destructor.
+*/
+static void line6_destruct(struct snd_card *card)
+{
+ struct usb_line6 *line6 = card->private_data;
+ struct usb_device *usbdev = line6->usbdev;
+
+ /* free buffer memory first: */
+ kfree(line6->buffer_message);
+ kfree(line6->buffer_listen);
+
+ /* then free URBs: */
+ usb_free_urb(line6->urb_listen);
+
+ /* decrement reference counters: */
+ usb_put_dev(usbdev);
+}
+
+/* get data from endpoint descriptor (see usb_maxpacket): */
+static void line6_get_interval(struct usb_line6 *line6)
+{
+ struct usb_device *usbdev = line6->usbdev;
+ struct usb_host_endpoint *ep;
+ unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
+ unsigned epnum = usb_pipeendpoint(pipe);
+
+ ep = usbdev->ep_in[epnum];
+ if (ep) {
+ line6->interval = ep->desc.bInterval;
+ line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ } else {
+ dev_err(line6->ifcdev,
+ "endpoint not available, using fallback values");
+ line6->interval = LINE6_FALLBACK_INTERVAL;
+ line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
+ }
+}
+
+static int line6_init_cap_control(struct usb_line6 *line6)
+{
+ int ret;
+
+ /* initialize USB buffers: */
+ line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
+ if (!line6->buffer_listen)
+ return -ENOMEM;
+
+ line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+ if (!line6->buffer_message)
+ return -ENOMEM;
+
+ line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
+ if (!line6->urb_listen)
+ return -ENOMEM;
+
+ ret = line6_start_listen(line6);
+ if (ret < 0) {
+ dev_err(line6->ifcdev, "cannot start listening: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ Probe USB device.
+*/
+int line6_probe(struct usb_interface *interface,
+ const struct usb_device_id *id,
+ const char *driver_name,
+ const struct line6_properties *properties,
+ int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+ size_t data_size)
+{
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+ struct snd_card *card;
+ struct usb_line6 *line6;
+ int interface_number;
+ int ret;
+
+ if (WARN_ON(data_size < sizeof(*line6)))
+ return -EINVAL;
+
+ /* we don't handle multiple configurations */
+ if (usbdev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ ret = snd_card_new(&interface->dev,
+ SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, data_size, &card);
+ if (ret < 0)
+ return ret;
+
+ /* store basic data: */
+ line6 = card->private_data;
+ line6->card = card;
+ line6->properties = properties;
+ line6->usbdev = usbdev;
+ line6->ifcdev = &interface->dev;
+
+ strcpy(card->id, properties->id);
+ strcpy(card->driver, driver_name);
+ strcpy(card->shortname, properties->name);
+ sprintf(card->longname, "Line 6 %s at USB %s", properties->name,
+ dev_name(line6->ifcdev));
+ card->private_free = line6_destruct;
+
+ usb_set_intfdata(interface, line6);
+
+ /* increment reference counters: */
+ usb_get_dev(usbdev);
+
+ /* initialize device info: */
+ dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
+
+ /* query interface number */
+ interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
+
+ ret = usb_set_interface(usbdev, interface_number,
+ properties->altsetting);
+ if (ret < 0) {
+ dev_err(&interface->dev, "set_interface failed\n");
+ goto error;
+ }
+
+ line6_get_interval(line6);
+
+ if (properties->capabilities & LINE6_CAP_CONTROL) {
+ ret = line6_init_cap_control(line6);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* initialize device data based on device: */
+ ret = private_init(line6, id);
+ if (ret < 0)
+ goto error;
+
+ /* creation of additional special files should go here */
+
+ dev_info(&interface->dev, "Line 6 %s now attached\n",
+ properties->name);
+
+ return 0;
+
+ error:
+ if (line6->disconnect)
+ line6->disconnect(line6);
+ snd_card_free(card);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(line6_probe);
+
+/*
+ Line 6 device disconnected.
+*/
+void line6_disconnect(struct usb_interface *interface)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ if (!line6)
+ return;
+
+ if (WARN_ON(usbdev != line6->usbdev))
+ return;
+
+ if (line6->urb_listen != NULL)
+ line6_stop_listen(line6);
+
+ snd_card_disconnect(line6->card);
+ if (line6->line6pcm)
+ line6_pcm_disconnect(line6->line6pcm);
+ if (line6->disconnect)
+ line6->disconnect(line6);
+
+ dev_info(&interface->dev, "Line 6 %s now disconnected\n",
+ line6->properties->name);
+
+ /* make sure the device isn't destructed twice: */
+ usb_set_intfdata(interface, NULL);
+
+ snd_card_free_when_closed(line6->card);
+}
+EXPORT_SYMBOL_GPL(line6_disconnect);
+
+#ifdef CONFIG_PM
+
+/*
+ Suspend Line 6 device.
+*/
+int line6_suspend(struct usb_interface *interface, pm_message_t message)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+ struct snd_line6_pcm *line6pcm = line6->line6pcm;
+
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
+
+ if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+ line6_stop_listen(line6);
+
+ if (line6pcm != NULL) {
+ snd_pcm_suspend_all(line6pcm->pcm);
+ line6pcm->flags = 0;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_suspend);
+
+/*
+ Resume Line 6 device.
+*/
+int line6_resume(struct usb_interface *interface)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+
+ if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+ line6_start_listen(line6);
+
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_resume);
+
+#endif /* CONFIG_PM */
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
new file mode 100644
index 000000000000..7da643e79e3b
--- /dev/null
+++ b/sound/usb/line6/driver.h
@@ -0,0 +1,181 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+
+#include "midi.h"
+
+#define USB_INTERVALS_PER_SECOND 1000
+
+/* Fallback USB interval and max packet size values */
+#define LINE6_FALLBACK_INTERVAL 10
+#define LINE6_FALLBACK_MAXPACKETSIZE 16
+
+#define LINE6_TIMEOUT 1
+#define LINE6_BUFSIZE_LISTEN 32
+#define LINE6_MESSAGE_MAXLEN 256
+
+/*
+ Line 6 MIDI control commands
+*/
+#define LINE6_PARAM_CHANGE 0xb0
+#define LINE6_PROGRAM_CHANGE 0xc0
+#define LINE6_SYSEX_BEGIN 0xf0
+#define LINE6_SYSEX_END 0xf7
+#define LINE6_RESET 0xff
+
+/*
+ MIDI channel for messages initiated by the host
+ (and eventually echoed back by the device)
+*/
+#define LINE6_CHANNEL_HOST 0x00
+
+/*
+ MIDI channel for messages initiated by the device
+*/
+#define LINE6_CHANNEL_DEVICE 0x02
+
+#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
+
+#define LINE6_CHANNEL_MASK 0x0f
+
+#define CHECK_STARTUP_PROGRESS(x, n) \
+do { \
+ if ((x) >= (n)) \
+ return; \
+ x = (n); \
+} while (0)
+
+extern const unsigned char line6_midi_id[3];
+
+static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
+static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
+
+/*
+ Common properties of Line 6 devices.
+*/
+struct line6_properties {
+ /* Card id string (maximum 16 characters).
+ * This can be used to address the device in ALSA programs as
+ * "default:CARD=<id>"
+ */
+ const char *id;
+
+ /* Card short name (maximum 32 characters) */
+ const char *name;
+
+ /* Bit vector defining this device's capabilities in line6usb driver */
+ int capabilities;
+
+ int altsetting;
+
+ unsigned ep_ctrl_r;
+ unsigned ep_ctrl_w;
+ unsigned ep_audio_r;
+ unsigned ep_audio_w;
+};
+
+/* Capability bits */
+enum {
+ /* device supports settings parameter via USB */
+ LINE6_CAP_CONTROL = 1 << 0,
+ /* device supports PCM input/output via USB */
+ LINE6_CAP_PCM = 1 << 1,
+ /* device support hardware monitoring */
+ LINE6_CAP_HWMON = 1 << 2,
+};
+
+/*
+ Common data shared by all Line 6 devices.
+ Corresponds to a pair of USB endpoints.
+*/
+struct usb_line6 {
+ /* USB device */
+ struct usb_device *usbdev;
+
+ /* Properties */
+ const struct line6_properties *properties;
+
+ /* Interval (ms) */
+ int interval;
+
+ /* Maximum size of USB packet */
+ int max_packet_size;
+
+ /* Device representing the USB interface */
+ struct device *ifcdev;
+
+ /* Line 6 sound card data structure.
+ * Each device has at least MIDI or PCM.
+ */
+ struct snd_card *card;
+
+ /* Line 6 PCM device data structure */
+ struct snd_line6_pcm *line6pcm;
+
+ /* Line 6 MIDI device data structure */
+ struct snd_line6_midi *line6midi;
+
+ /* URB for listening to PODxt Pro control endpoint */
+ struct urb *urb_listen;
+
+ /* Buffer for listening to PODxt Pro control endpoint */
+ unsigned char *buffer_listen;
+
+ /* Buffer for message to be processed */
+ unsigned char *buffer_message;
+
+ /* Length of message to be processed */
+ int message_length;
+
+ void (*process_message)(struct usb_line6 *);
+ void (*disconnect)(struct usb_line6 *line6);
+};
+
+extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
+ int code2, int size);
+extern int line6_read_data(struct usb_line6 *line6, unsigned address,
+ void *data, unsigned datalen);
+extern int line6_read_serial_number(struct usb_line6 *line6,
+ u32 *serial_number);
+extern int line6_send_raw_message_async(struct usb_line6 *line6,
+ const char *buffer, int size);
+extern int line6_send_sysex_message(struct usb_line6 *line6,
+ const char *buffer, int size);
+extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+extern void line6_start_timer(struct timer_list *timer, unsigned long msecs,
+ void (*function)(unsigned long),
+ unsigned long data);
+extern int line6_version_request_async(struct usb_line6 *line6);
+extern int line6_write_data(struct usb_line6 *line6, unsigned address,
+ void *data, unsigned datalen);
+
+int line6_probe(struct usb_interface *interface,
+ const struct usb_device_id *id,
+ const char *driver_name,
+ const struct line6_properties *properties,
+ int (*private_init)(struct usb_line6 *, const struct usb_device_id *id),
+ size_t data_size);
+
+void line6_disconnect(struct usb_interface *interface);
+
+#ifdef CONFIG_PM
+int line6_suspend(struct usb_interface *interface, pm_message_t message);
+int line6_resume(struct usb_interface *interface);
+#endif
+
+#endif
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
new file mode 100644
index 000000000000..cebea9b7f769
--- /dev/null
+++ b/sound/usb/line6/midi.c
@@ -0,0 +1,292 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+
+#include "driver.h"
+#include "midi.h"
+
+#define line6_rawmidi_substream_midi(substream) \
+ ((struct snd_line6_midi *)((substream)->rmidi->private_data))
+
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+ int length);
+
+/*
+ Pass data received via USB to MIDI.
+*/
+void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+ int length)
+{
+ if (line6->line6midi->substream_receive)
+ snd_rawmidi_receive(line6->line6midi->substream_receive,
+ data, length);
+}
+
+/*
+ Read data from MIDI buffer and transmit them via USB.
+*/
+static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+ struct snd_line6_midi *line6midi = line6->line6midi;
+ struct midi_buffer *mb = &line6midi->midibuf_out;
+ unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
+ int req, done;
+
+ for (;;) {
+ req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
+ done = snd_rawmidi_transmit_peek(substream, chunk, req);
+
+ if (done == 0)
+ break;
+
+ line6_midibuf_write(mb, chunk, done);
+ snd_rawmidi_transmit_ack(substream, done);
+ }
+
+ for (;;) {
+ done = line6_midibuf_read(mb, chunk,
+ LINE6_FALLBACK_MAXPACKETSIZE);
+
+ if (done == 0)
+ break;
+
+ send_midi_async(line6, chunk, done);
+ }
+}
+
+/*
+ Notification of completion of MIDI transmission.
+*/
+static void midi_sent(struct urb *urb)
+{
+ unsigned long flags;
+ int status;
+ int num;
+ struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+
+ status = urb->status;
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+
+ if (status == -ESHUTDOWN)
+ return;
+
+ spin_lock_irqsave(&line6->line6midi->lock, flags);
+ num = --line6->line6midi->num_active_send_urbs;
+
+ if (num == 0) {
+ line6_midi_transmit(line6->line6midi->substream_transmit);
+ num = line6->line6midi->num_active_send_urbs;
+ }
+
+ if (num == 0)
+ wake_up(&line6->line6midi->send_wait);
+
+ spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+/*
+ Send an asynchronous MIDI message.
+ Assumes that line6->line6midi->lock is held
+ (i.e., this function is serialized).
+*/
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+ int length)
+{
+ struct urb *urb;
+ int retval;
+ unsigned char *transfer_buffer;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
+
+ if (transfer_buffer == NULL) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(urb, line6->usbdev,
+ usb_sndbulkpipe(line6->usbdev,
+ line6->properties->ep_ctrl_w),
+ transfer_buffer, length, midi_sent, line6,
+ line6->interval);
+ urb->actual_length = 0;
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (retval < 0) {
+ dev_err(line6->ifcdev, "usb_submit_urb failed\n");
+ usb_free_urb(urb);
+ return retval;
+ }
+
+ ++line6->line6midi->num_active_send_urbs;
+ return 0;
+}
+
+static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ unsigned long flags;
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+
+ line6->line6midi->substream_transmit = substream;
+ spin_lock_irqsave(&line6->line6midi->lock, flags);
+
+ if (line6->line6midi->num_active_send_urbs == 0)
+ line6_midi_transmit(substream);
+
+ spin_unlock_irqrestore(&line6->line6midi->lock, flags);
+}
+
+static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+ struct snd_line6_midi *midi = line6->line6midi;
+
+ wait_event_interruptible(midi->send_wait,
+ midi->num_active_send_urbs == 0);
+}
+
+static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+ return 0;
+}
+
+static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
+ int up)
+{
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+
+ if (up)
+ line6->line6midi->substream_receive = substream;
+ else
+ line6->line6midi->substream_receive = NULL;
+}
+
+static struct snd_rawmidi_ops line6_midi_output_ops = {
+ .open = line6_midi_output_open,
+ .close = line6_midi_output_close,
+ .trigger = line6_midi_output_trigger,
+ .drain = line6_midi_output_drain,
+};
+
+static struct snd_rawmidi_ops line6_midi_input_ops = {
+ .open = line6_midi_input_open,
+ .close = line6_midi_input_close,
+ .trigger = line6_midi_input_trigger,
+};
+
+/* Create a MIDI device */
+static int snd_line6_new_midi(struct usb_line6 *line6,
+ struct snd_rawmidi **rmidi_ret)
+{
+ struct snd_rawmidi *rmidi;
+ int err;
+
+ err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
+ if (err < 0)
+ return err;
+
+ rmidi = *rmidi_ret;
+ strcpy(rmidi->id, line6->properties->id);
+ strcpy(rmidi->name, line6->properties->name);
+
+ rmidi->info_flags =
+ SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &line6_midi_output_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &line6_midi_input_ops);
+ return 0;
+}
+
+/* MIDI device destructor */
+static void snd_line6_midi_free(struct snd_rawmidi *rmidi)
+{
+ struct snd_line6_midi *line6midi = rmidi->private_data;
+
+ line6_midibuf_destroy(&line6midi->midibuf_in);
+ line6_midibuf_destroy(&line6midi->midibuf_out);
+ kfree(line6midi);
+}
+
+/*
+ Initialize the Line 6 MIDI subsystem.
+*/
+int line6_init_midi(struct usb_line6 *line6)
+{
+ int err;
+ struct snd_rawmidi *rmidi;
+ struct snd_line6_midi *line6midi;
+
+ if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
+ /* skip MIDI initialization and report success */
+ return 0;
+ }
+
+ err = snd_line6_new_midi(line6, &rmidi);
+ if (err < 0)
+ return err;
+
+ line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+ if (!line6midi)
+ return -ENOMEM;
+
+ rmidi->private_data = line6midi;
+ rmidi->private_free = snd_line6_midi_free;
+
+ init_waitqueue_head(&line6midi->send_wait);
+ spin_lock_init(&line6midi->lock);
+ line6midi->line6 = line6;
+
+ err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
+ if (err < 0)
+ return err;
+
+ err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
+ if (err < 0)
+ return err;
+
+ line6->line6midi = line6midi;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_midi);
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h
new file mode 100644
index 000000000000..cf82d69e2747
--- /dev/null
+++ b/sound/usb/line6/midi.h
@@ -0,0 +1,51 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef MIDI_H
+#define MIDI_H
+
+#include <sound/rawmidi.h>
+
+#include "midibuf.h"
+
+#define MIDI_BUFFER_SIZE 1024
+
+struct snd_line6_midi {
+ /* Pointer back to the Line 6 driver data structure */
+ struct usb_line6 *line6;
+
+ /* MIDI substream for receiving (or NULL if not active) */
+ struct snd_rawmidi_substream *substream_receive;
+
+ /* MIDI substream for transmitting (or NULL if not active) */
+ struct snd_rawmidi_substream *substream_transmit;
+
+ /* Number of currently active MIDI send URBs */
+ int num_active_send_urbs;
+
+ /* Spin lock to protect MIDI buffer handling */
+ spinlock_t lock;
+
+ /* Wait queue for MIDI transmission */
+ wait_queue_head_t send_wait;
+
+ /* Buffer for incoming MIDI stream */
+ struct midi_buffer midibuf_in;
+
+ /* Buffer for outgoing MIDI stream */
+ struct midi_buffer midibuf_out;
+};
+
+extern int line6_init_midi(struct usb_line6 *line6);
+extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+ int length);
+
+#endif
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c
new file mode 100644
index 000000000000..36a610ba342e
--- /dev/null
+++ b/sound/usb/line6/midibuf.c
@@ -0,0 +1,252 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+
+#include "midibuf.h"
+
+static int midibuf_message_length(unsigned char code)
+{
+ int message_length;
+
+ if (code < 0x80)
+ message_length = -1;
+ else if (code < 0xf0) {
+ static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
+
+ message_length = length[(code >> 4) - 8];
+ } else {
+ /*
+ Note that according to the MIDI specification 0xf2 is
+ the "Song Position Pointer", but this is used by Line 6
+ to send sysex messages to the host.
+ */
+ static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
+ 1, 1, 1, -1, 1, 1
+ };
+ message_length = length[code & 0x0f];
+ }
+
+ return message_length;
+}
+
+static int midibuf_is_empty(struct midi_buffer *this)
+{
+ return (this->pos_read == this->pos_write) && !this->full;
+}
+
+static int midibuf_is_full(struct midi_buffer *this)
+{
+ return this->full;
+}
+
+void line6_midibuf_reset(struct midi_buffer *this)
+{
+ this->pos_read = this->pos_write = this->full = 0;
+ this->command_prev = -1;
+}
+
+int line6_midibuf_init(struct midi_buffer *this, int size, int split)
+{
+ this->buf = kmalloc(size, GFP_KERNEL);
+
+ if (this->buf == NULL)
+ return -ENOMEM;
+
+ this->size = size;
+ this->split = split;
+ line6_midibuf_reset(this);
+ return 0;
+}
+
+int line6_midibuf_bytes_free(struct midi_buffer *this)
+{
+ return
+ midibuf_is_full(this) ?
+ 0 :
+ (this->pos_read - this->pos_write + this->size - 1) % this->size +
+ 1;
+}
+
+int line6_midibuf_bytes_used(struct midi_buffer *this)
+{
+ return
+ midibuf_is_empty(this) ?
+ 0 :
+ (this->pos_write - this->pos_read + this->size - 1) % this->size +
+ 1;
+}
+
+int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
+ int length)
+{
+ int bytes_free;
+ int length1, length2;
+ int skip_active_sense = 0;
+
+ if (midibuf_is_full(this) || (length <= 0))
+ return 0;
+
+ /* skip trailing active sense */
+ if (data[length - 1] == 0xfe) {
+ --length;
+ skip_active_sense = 1;
+ }
+
+ bytes_free = line6_midibuf_bytes_free(this);
+
+ if (length > bytes_free)
+ length = bytes_free;
+
+ if (length > 0) {
+ length1 = this->size - this->pos_write;
+
+ if (length < length1) {
+ /* no buffer wraparound */
+ memcpy(this->buf + this->pos_write, data, length);
+ this->pos_write += length;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+ memcpy(this->buf + this->pos_write, data, length1);
+ memcpy(this->buf, data + length1, length2);
+ this->pos_write = length2;
+ }
+
+ if (this->pos_write == this->pos_read)
+ this->full = 1;
+ }
+
+ return length + skip_active_sense;
+}
+
+int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
+ int length)
+{
+ int bytes_used;
+ int length1, length2;
+ int command;
+ int midi_length;
+ int repeat = 0;
+ int i;
+
+ /* we need to be able to store at least a 3 byte MIDI message */
+ if (length < 3)
+ return -EINVAL;
+
+ if (midibuf_is_empty(this))
+ return 0;
+
+ bytes_used = line6_midibuf_bytes_used(this);
+
+ if (length > bytes_used)
+ length = bytes_used;
+
+ length1 = this->size - this->pos_read;
+
+ /* check MIDI command length */
+ command = this->buf[this->pos_read];
+
+ if (command & 0x80) {
+ midi_length = midibuf_message_length(command);
+ this->command_prev = command;
+ } else {
+ if (this->command_prev > 0) {
+ int midi_length_prev =
+ midibuf_message_length(this->command_prev);
+
+ if (midi_length_prev > 0) {
+ midi_length = midi_length_prev - 1;
+ repeat = 1;
+ } else
+ midi_length = -1;
+ } else
+ midi_length = -1;
+ }
+
+ if (midi_length < 0) {
+ /* search for end of message */
+ if (length < length1) {
+ /* no buffer wraparound */
+ for (i = 1; i < length; ++i)
+ if (this->buf[this->pos_read + i] & 0x80)
+ break;
+
+ midi_length = i;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+
+ for (i = 1; i < length1; ++i)
+ if (this->buf[this->pos_read + i] & 0x80)
+ break;
+
+ if (i < length1)
+ midi_length = i;
+ else {
+ for (i = 0; i < length2; ++i)
+ if (this->buf[i] & 0x80)
+ break;
+
+ midi_length = length1 + i;
+ }
+ }
+
+ if (midi_length == length)
+ midi_length = -1; /* end of message not found */
+ }
+
+ if (midi_length < 0) {
+ if (!this->split)
+ return 0; /* command is not yet complete */
+ } else {
+ if (length < midi_length)
+ return 0; /* command is not yet complete */
+
+ length = midi_length;
+ }
+
+ if (length < length1) {
+ /* no buffer wraparound */
+ memcpy(data + repeat, this->buf + this->pos_read, length);
+ this->pos_read += length;
+ } else {
+ /* buffer wraparound */
+ length2 = length - length1;
+ memcpy(data + repeat, this->buf + this->pos_read, length1);
+ memcpy(data + repeat + length1, this->buf, length2);
+ this->pos_read = length2;
+ }
+
+ if (repeat)
+ data[0] = this->command_prev;
+
+ this->full = 0;
+ return length + repeat;
+}
+
+int line6_midibuf_ignore(struct midi_buffer *this, int length)
+{
+ int bytes_used = line6_midibuf_bytes_used(this);
+
+ if (length > bytes_used)
+ length = bytes_used;
+
+ this->pos_read = (this->pos_read + length) % this->size;
+ this->full = 0;
+ return length;
+}
+
+void line6_midibuf_destroy(struct midi_buffer *this)
+{
+ kfree(this->buf);
+ this->buf = NULL;
+}
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h
new file mode 100644
index 000000000000..6ea21ffb6627
--- /dev/null
+++ b/sound/usb/line6/midibuf.h
@@ -0,0 +1,35 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef MIDIBUF_H
+#define MIDIBUF_H
+
+struct midi_buffer {
+ unsigned char *buf;
+ int size;
+ int split;
+ int pos_read, pos_write;
+ int full;
+ int command_prev;
+};
+
+extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
+extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
+extern void line6_midibuf_destroy(struct midi_buffer *mb);
+extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
+extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
+extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
+ int length);
+extern void line6_midibuf_reset(struct midi_buffer *mb);
+extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
+ int length);
+
+#endif
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
new file mode 100644
index 000000000000..8461d6bf992f
--- /dev/null
+++ b/sound/usb/line6/pcm.c
@@ -0,0 +1,588 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+/* impulse response volume controls */
+static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 255;
+ return 0;
+}
+
+static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
+ return 0;
+}
+
+static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int value = ucontrol->value.integer.value[0];
+ int err;
+
+ if (line6pcm->impulse_volume == value)
+ return 0;
+
+ line6pcm->impulse_volume = value;
+ if (value > 0) {
+ err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE);
+ if (err < 0) {
+ line6pcm->impulse_volume = 0;
+ line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+ return err;
+ }
+ } else {
+ line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
+ }
+ return 1;
+}
+
+/* impulse response period controls */
+static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 2000;
+ return 0;
+}
+
+static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->impulse_period;
+ return 0;
+}
+
+static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int value = ucontrol->value.integer.value[0];
+
+ if (line6pcm->impulse_period == value)
+ return 0;
+
+ line6pcm->impulse_period = value;
+ return 1;
+}
+
+/*
+ Unlink all currently active URBs.
+*/
+static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pcms)
+{
+ int i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (test_bit(i, &pcms->active_urbs)) {
+ if (!test_and_set_bit(i, &pcms->unlink_urbs))
+ usb_unlink_urb(pcms->urbs[i]);
+ }
+ }
+}
+
+/*
+ Wait until unlinking of all currently active URBs has been finished.
+*/
+static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pcms)
+{
+ int timeout = HZ;
+ int i;
+ int alive;
+
+ do {
+ alive = 0;
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (test_bit(i, &pcms->active_urbs))
+ alive++;
+ }
+ if (!alive)
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ } while (--timeout > 0);
+ if (alive)
+ dev_err(line6pcm->line6->ifcdev,
+ "timeout: still %d active urbs..\n", alive);
+}
+
+static inline struct line6_pcm_stream *
+get_stream(struct snd_line6_pcm *line6pcm, int direction)
+{
+ return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?
+ &line6pcm->out : &line6pcm->in;
+}
+
+/* allocate a buffer if not opened yet;
+ * call this in line6pcm.state_change mutex
+ */
+static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pstr, int type)
+{
+ /* Invoked multiple times in a row so allocate once only */
+ if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {
+ pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+ line6pcm->max_packet_size, GFP_KERNEL);
+ if (!pstr->buffer)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/* free a buffer if all streams are closed;
+ * call this in line6pcm.state_change mutex
+ */
+static void line6_buffer_release(struct snd_line6_pcm *line6pcm,
+ struct line6_pcm_stream *pstr, int type)
+{
+
+ clear_bit(type, &pstr->opened);
+ if (!pstr->opened) {
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+ kfree(pstr->buffer);
+ pstr->buffer = NULL;
+ }
+}
+
+/* start a PCM stream */
+static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
+ int type)
+{
+ unsigned long flags;
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+ int ret = 0;
+
+ spin_lock_irqsave(&pstr->lock, flags);
+ if (!test_and_set_bit(type, &pstr->running)) {
+ if (pstr->active_urbs || pstr->unlink_urbs) {
+ ret = -EBUSY;
+ goto error;
+ }
+
+ pstr->count = 0;
+ /* Submit all currently available URBs */
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = line6_submit_audio_out_all_urbs(line6pcm);
+ else
+ ret = line6_submit_audio_in_all_urbs(line6pcm);
+ }
+ error:
+ if (ret < 0)
+ clear_bit(type, &pstr->running);
+ spin_unlock_irqrestore(&pstr->lock, flags);
+ return ret;
+}
+
+/* stop a PCM stream; this doesn't sync with the unlinked URBs */
+static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
+ int type)
+{
+ unsigned long flags;
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
+
+ spin_lock_irqsave(&pstr->lock, flags);
+ clear_bit(type, &pstr->running);
+ if (!pstr->running) {
+ line6_unlink_audio_urbs(line6pcm, pstr);
+ if (direction == SNDRV_PCM_STREAM_CAPTURE) {
+ line6pcm->prev_fbuf = NULL;
+ line6pcm->prev_fsize = 0;
+ }
+ }
+ spin_unlock_irqrestore(&pstr->lock, flags);
+}
+
+/* common PCM trigger callback */
+int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct snd_pcm_substream *s;
+ int err;
+
+ clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
+
+ snd_pcm_group_for_each_entry(s, substream) {
+ if (s->pcm->card != substream->pcm->card)
+ continue;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ err = line6_stream_start(line6pcm, s->stream,
+ LINE6_STREAM_PCM);
+ if (err < 0)
+ return err;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ line6_stream_stop(line6pcm, s->stream,
+ LINE6_STREAM_PCM);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* common PCM pointer callback */
+snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ return pstr->pos_done;
+}
+
+/* Acquire and start duplex streams:
+ * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
+ */
+int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type)
+{
+ struct line6_pcm_stream *pstr;
+ int ret = 0, dir;
+
+ mutex_lock(&line6pcm->state_mutex);
+ for (dir = 0; dir < 2; dir++) {
+ pstr = get_stream(line6pcm, dir);
+ ret = line6_buffer_acquire(line6pcm, pstr, type);
+ if (ret < 0)
+ goto error;
+ if (!pstr->running)
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+ }
+ for (dir = 0; dir < 2; dir++) {
+ ret = line6_stream_start(line6pcm, dir, type);
+ if (ret < 0)
+ goto error;
+ }
+ error:
+ mutex_unlock(&line6pcm->state_mutex);
+ if (ret < 0)
+ line6_pcm_release(line6pcm, type);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(line6_pcm_acquire);
+
+/* Stop and release duplex streams */
+void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
+{
+ struct line6_pcm_stream *pstr;
+ int dir;
+
+ mutex_lock(&line6pcm->state_mutex);
+ for (dir = 0; dir < 2; dir++)
+ line6_stream_stop(line6pcm, dir, type);
+ for (dir = 0; dir < 2; dir++) {
+ pstr = get_stream(line6pcm, dir);
+ line6_buffer_release(line6pcm, pstr, type);
+ }
+ mutex_unlock(&line6pcm->state_mutex);
+}
+EXPORT_SYMBOL_GPL(line6_pcm_release);
+
+/* common PCM hw_params callback */
+int snd_line6_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ int ret;
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM);
+ if (ret < 0)
+ goto error;
+
+ ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0) {
+ line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+ goto error;
+ }
+
+ pstr->period = params_period_bytes(hw_params);
+ error:
+ mutex_unlock(&line6pcm->state_mutex);
+ return ret;
+}
+
+/* common PCM hw_free callback */
+int snd_line6_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
+ mutex_unlock(&line6pcm->state_mutex);
+ return snd_pcm_lib_free_pages(substream);
+}
+
+
+/* control info callback */
+static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 256;
+ return 0;
+}
+
+/* control get callback */
+static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i;
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ for (i = 0; i < 2; i++)
+ ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
+
+ return 0;
+}
+
+/* control put callback */
+static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int i, changed = 0;
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ for (i = 0; i < 2; i++)
+ if (line6pcm->volume_playback[i] !=
+ ucontrol->value.integer.value[i]) {
+ line6pcm->volume_playback[i] =
+ ucontrol->value.integer.value[i];
+ changed = 1;
+ }
+
+ return changed;
+}
+
+/* control definition */
+static struct snd_kcontrol_new line6_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = snd_line6_control_playback_info,
+ .get = snd_line6_control_playback_get,
+ .put = snd_line6_control_playback_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Impulse Response Volume",
+ .info = snd_line6_impulse_volume_info,
+ .get = snd_line6_impulse_volume_get,
+ .put = snd_line6_impulse_volume_put
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Impulse Response Period",
+ .info = snd_line6_impulse_period_info,
+ .get = snd_line6_impulse_period_get,
+ .put = snd_line6_impulse_period_put
+ },
+};
+
+/*
+ Cleanup the PCM device.
+*/
+static void cleanup_urbs(struct line6_pcm_stream *pcms)
+{
+ int i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; i++) {
+ if (pcms->urbs[i]) {
+ usb_kill_urb(pcms->urbs[i]);
+ usb_free_urb(pcms->urbs[i]);
+ }
+ }
+}
+
+static void line6_cleanup_pcm(struct snd_pcm *pcm)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
+
+ cleanup_urbs(&line6pcm->out);
+ cleanup_urbs(&line6pcm->in);
+ kfree(line6pcm);
+}
+
+/* create a PCM device */
+static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(line6->card, (char *)line6->properties->name,
+ 0, 1, 1, pcm_ret);
+ if (err < 0)
+ return err;
+ pcm = *pcm_ret;
+ strcpy(pcm->name, line6->properties->name);
+
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_line6_playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
+
+ /* pre-allocation of buffers */
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL), 64 * 1024,
+ 128 * 1024);
+ return 0;
+}
+
+/*
+ Sync with PCM stream stops.
+*/
+void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
+{
+ line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
+ line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
+ line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
+ line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
+}
+
+/*
+ Create and register the PCM device and mixer entries.
+ Create URBs for playback and capture.
+*/
+int line6_init_pcm(struct usb_line6 *line6,
+ struct line6_pcm_properties *properties)
+{
+ int i, err;
+ unsigned ep_read = line6->properties->ep_audio_r;
+ unsigned ep_write = line6->properties->ep_audio_w;
+ struct snd_pcm *pcm;
+ struct snd_line6_pcm *line6pcm;
+
+ if (!(line6->properties->capabilities & LINE6_CAP_PCM))
+ return 0; /* skip PCM initialization and report success */
+
+ err = snd_line6_new_pcm(line6, &pcm);
+ if (err < 0)
+ return err;
+
+ line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
+ if (!line6pcm)
+ return -ENOMEM;
+
+ mutex_init(&line6pcm->state_mutex);
+ line6pcm->pcm = pcm;
+ line6pcm->properties = properties;
+ line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
+ line6pcm->volume_monitor = 255;
+ line6pcm->line6 = line6;
+
+ /* Read and write buffers are sized identically, so choose minimum */
+ line6pcm->max_packet_size = min(
+ usb_maxpacket(line6->usbdev,
+ usb_rcvisocpipe(line6->usbdev, ep_read), 0),
+ usb_maxpacket(line6->usbdev,
+ usb_sndisocpipe(line6->usbdev, ep_write), 1));
+
+ spin_lock_init(&line6pcm->out.lock);
+ spin_lock_init(&line6pcm->in.lock);
+ line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
+
+ line6->line6pcm = line6pcm;
+
+ pcm->private_data = line6pcm;
+ pcm->private_free = line6_cleanup_pcm;
+
+ err = line6_create_audio_out_urbs(line6pcm);
+ if (err < 0)
+ return err;
+
+ err = line6_create_audio_in_urbs(line6pcm);
+ if (err < 0)
+ return err;
+
+ /* mixer: */
+ for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&line6_controls[i], line6pcm));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(line6_init_pcm);
+
+/* prepare pcm callback */
+int snd_line6_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
+
+ mutex_lock(&line6pcm->state_mutex);
+ if (!pstr->running)
+ line6_wait_clear_audio_urbs(line6pcm, pstr);
+
+ if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
+ line6pcm->out.count = 0;
+ line6pcm->out.pos = 0;
+ line6pcm->out.pos_done = 0;
+ line6pcm->out.bytes = 0;
+ line6pcm->in.count = 0;
+ line6pcm->in.pos_done = 0;
+ line6pcm->in.bytes = 0;
+ }
+
+ mutex_unlock(&line6pcm->state_mutex);
+ return 0;
+}
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h
new file mode 100644
index 000000000000..508410adbd51
--- /dev/null
+++ b/sound/usb/line6/pcm.h
@@ -0,0 +1,197 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+/*
+ PCM interface to POD series devices.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/* number of URBs */
+#define LINE6_ISO_BUFFERS 2
+
+/*
+ number of USB frames per URB
+ The Line 6 Windows driver always transmits two frames per packet, but
+ the Linux driver performs significantly better (i.e., lower latency)
+ with only one frame per packet.
+*/
+#define LINE6_ISO_PACKETS 1
+
+/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
+#define LINE6_ISO_INTERVAL 1
+
+#define LINE6_IMPULSE_DEFAULT_PERIOD 100
+
+/*
+ Get substream from Line 6 PCM data structure
+*/
+#define get_substream(line6pcm, stream) \
+ (line6pcm->pcm->streams[stream].substream)
+
+/*
+ PCM mode bits.
+
+ There are several features of the Line 6 USB driver which require PCM
+ data to be exchanged with the device:
+ *) PCM playback and capture via ALSA
+ *) software monitoring (for devices without hardware monitoring)
+ *) optional impulse response measurement
+ However, from the device's point of view, there is just a single
+ capture and playback stream, which must be shared between these
+ subsystems. It is therefore necessary to maintain the state of the
+ subsystems with respect to PCM usage.
+
+ We define two bit flags, "opened" and "running", for each playback
+ or capture stream. Both can contain the bit flag corresponding to
+ LINE6_STREAM_* type,
+ LINE6_STREAM_PCM = ALSA PCM playback or capture
+ LINE6_STREAM_MONITOR = software monitoring
+ IMPULSE = optional impulse response measurement
+ The opened flag indicates whether the buffer is allocated while
+ the running flag indicates whether the stream is running.
+
+ For monitor or impulse operations, the driver needs to call
+ line6_pcm_acquire() or line6_pcm_release() with the appropriate
+ LINE6_STREAM_* flag.
+*/
+
+/* stream types */
+enum {
+ LINE6_STREAM_PCM,
+ LINE6_STREAM_MONITOR,
+ LINE6_STREAM_IMPULSE,
+};
+
+/* misc bit flags for PCM operation */
+enum {
+ LINE6_FLAG_PAUSE_PLAYBACK,
+ LINE6_FLAG_PREPARED,
+};
+
+struct line6_pcm_properties {
+ struct snd_pcm_hardware playback_hw, capture_hw;
+ struct snd_pcm_hw_constraint_ratdens rates;
+ int bytes_per_frame;
+};
+
+struct line6_pcm_stream {
+ /* allocated URBs */
+ struct urb *urbs[LINE6_ISO_BUFFERS];
+
+ /* Temporary buffer;
+ * Since the packet size is not known in advance, this buffer is
+ * large enough to store maximum size packets.
+ */
+ unsigned char *buffer;
+
+ /* Free frame position in the buffer. */
+ snd_pcm_uframes_t pos;
+
+ /* Count processed bytes;
+ * This is modulo period size (to determine when a period is finished).
+ */
+ unsigned bytes;
+
+ /* Counter to create desired sample rate */
+ unsigned count;
+
+ /* period size in bytes */
+ unsigned period;
+
+ /* Processed frame position in the buffer;
+ * The contents of the ring buffer have been consumed by the USB
+ * subsystem (i.e., sent to the USB device) up to this position.
+ */
+ snd_pcm_uframes_t pos_done;
+
+ /* Bit mask of active URBs */
+ unsigned long active_urbs;
+
+ /* Bit mask of URBs currently being unlinked */
+ unsigned long unlink_urbs;
+
+ /* Spin lock to protect updates of the buffer positions (not contents)
+ */
+ spinlock_t lock;
+
+ /* Bit flags for operational stream types */
+ unsigned long opened;
+
+ /* Bit flags for running stream types */
+ unsigned long running;
+
+ int last_frame;
+};
+
+struct snd_line6_pcm {
+ /* Pointer back to the Line 6 driver data structure */
+ struct usb_line6 *line6;
+
+ /* Properties. */
+ struct line6_pcm_properties *properties;
+
+ /* ALSA pcm stream */
+ struct snd_pcm *pcm;
+
+ /* protection to state changes of in/out streams */
+ struct mutex state_mutex;
+
+ /* Capture and playback streams */
+ struct line6_pcm_stream in;
+ struct line6_pcm_stream out;
+
+ /* Previously captured frame (for software monitoring) */
+ unsigned char *prev_fbuf;
+
+ /* Size of previously captured frame (for software monitoring) */
+ int prev_fsize;
+
+ /* Maximum size of USB packet */
+ int max_packet_size;
+
+ /* PCM playback volume (left and right) */
+ int volume_playback[2];
+
+ /* PCM monitor volume */
+ int volume_monitor;
+
+ /* Volume of impulse response test signal (if zero, test is disabled) */
+ int impulse_volume;
+
+ /* Period of impulse response test signal */
+ int impulse_period;
+
+ /* Counter for impulse response test signal */
+ int impulse_count;
+
+ /* Several status bits (see LINE6_FLAG_*) */
+ unsigned long flags;
+};
+
+extern int line6_init_pcm(struct usb_line6 *line6,
+ struct line6_pcm_properties *properties);
+extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
+extern int snd_line6_prepare(struct snd_pcm_substream *substream);
+extern int snd_line6_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params);
+extern int snd_line6_hw_free(struct snd_pcm_substream *substream);
+extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream);
+extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
+extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type);
+extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type);
+
+#endif
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c
new file mode 100644
index 000000000000..05dee690f487
--- /dev/null
+++ b/sound/usb/line6/playback.c
@@ -0,0 +1,429 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "pcm.h"
+#include "playback.h"
+
+/*
+ Software stereo volume control.
+*/
+static void change_volume(struct urb *urb_out, int volume[],
+ int bytes_per_frame)
+{
+ int chn = 0;
+
+ if (volume[0] == 256 && volume[1] == 256)
+ return; /* maximum volume - no change */
+
+ if (bytes_per_frame == 4) {
+ __le16 *p, *buf_end;
+
+ p = (__le16 *)urb_out->transfer_buffer;
+ buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
+
+ for (; p < buf_end; ++p) {
+ short pv = le16_to_cpu(*p);
+ int val = (pv * volume[chn & 1]) >> 8;
+ pv = clamp(val, 0x7fff, -0x8000);
+ *p = cpu_to_le16(pv);
+ ++chn;
+ }
+ } else if (bytes_per_frame == 6) {
+ unsigned char *p, *buf_end;
+
+ p = (unsigned char *)urb_out->transfer_buffer;
+ buf_end = p + urb_out->transfer_buffer_length;
+
+ for (; p < buf_end; p += 3) {
+ int val;
+
+ val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
+ val = (val * volume[chn & 1]) >> 8;
+ val = clamp(val, 0x7fffff, -0x800000);
+ p[0] = val;
+ p[1] = val >> 8;
+ p[2] = val >> 16;
+ ++chn;
+ }
+ }
+}
+
+/*
+ Create signal for impulse response test.
+*/
+static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
+ struct urb *urb_out, int bytes_per_frame)
+{
+ int frames = urb_out->transfer_buffer_length / bytes_per_frame;
+
+ if (bytes_per_frame == 4) {
+ int i;
+ short *pi = (short *)line6pcm->prev_fbuf;
+ short *po = (short *)urb_out->transfer_buffer;
+
+ for (i = 0; i < frames; ++i) {
+ po[0] = pi[0];
+ po[1] = 0;
+ pi += 2;
+ po += 2;
+ }
+ } else if (bytes_per_frame == 6) {
+ int i, j;
+ unsigned char *pi = line6pcm->prev_fbuf;
+ unsigned char *po = urb_out->transfer_buffer;
+
+ for (i = 0; i < frames; ++i) {
+ for (j = 0; j < bytes_per_frame / 2; ++j)
+ po[j] = pi[j];
+
+ for (; j < bytes_per_frame; ++j)
+ po[j] = 0;
+
+ pi += bytes_per_frame;
+ po += bytes_per_frame;
+ }
+ }
+ if (--line6pcm->impulse_count <= 0) {
+ ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
+ 1] =
+ line6pcm->impulse_volume;
+ line6pcm->impulse_count = line6pcm->impulse_period;
+ }
+}
+
+/*
+ Add signal to buffer for software monitoring.
+*/
+static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
+ int volume, int bytes_per_frame)
+{
+ if (volume == 0)
+ return; /* zero volume - no change */
+
+ if (bytes_per_frame == 4) {
+ __le16 *pi, *po, *buf_end;
+
+ pi = (__le16 *)signal;
+ po = (__le16 *)urb_out->transfer_buffer;
+ buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
+
+ for (; po < buf_end; ++pi, ++po) {
+ short pov = le16_to_cpu(*po);
+ short piv = le16_to_cpu(*pi);
+ int val = pov + ((piv * volume) >> 8);
+ pov = clamp(val, 0x7fff, -0x8000);
+ *po = cpu_to_le16(pov);
+ }
+ }
+
+ /*
+ We don't need to handle devices with 6 bytes per frame here
+ since they all support hardware monitoring.
+ */
+}
+
+/*
+ Find a free URB, prepare audio data, and submit URB.
+ must be called in line6pcm->out.lock context
+*/
+static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
+{
+ int index;
+ int i, urb_size, urb_frames;
+ int ret;
+ const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+ const int frame_increment =
+ line6pcm->properties->rates.rats[0].num_min;
+ const int frame_factor =
+ line6pcm->properties->rates.rats[0].den *
+ (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
+ struct urb *urb_out;
+
+ index =
+ find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS);
+
+ if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+ return -EINVAL;
+ }
+
+ urb_out = line6pcm->out.urbs[index];
+ urb_size = 0;
+
+ for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+ /* compute frame size for given sampling rate */
+ int fsize = 0;
+ struct usb_iso_packet_descriptor *fout =
+ &urb_out->iso_frame_desc[i];
+
+ fsize = line6pcm->prev_fsize;
+ if (fsize == 0) {
+ int n;
+
+ line6pcm->out.count += frame_increment;
+ n = line6pcm->out.count / frame_factor;
+ line6pcm->out.count -= n * frame_factor;
+ fsize = n * bytes_per_frame;
+ }
+
+ fout->offset = urb_size;
+ fout->length = fsize;
+ urb_size += fsize;
+ }
+
+ if (urb_size == 0) {
+ /* can't determine URB size */
+ dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
+ return -EINVAL;
+ }
+
+ urb_frames = urb_size / bytes_per_frame;
+ urb_out->transfer_buffer =
+ line6pcm->out.buffer +
+ index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+ urb_out->transfer_buffer_length = urb_size;
+ urb_out->context = line6pcm;
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) &&
+ !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) {
+ struct snd_pcm_runtime *runtime =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
+
+ if (line6pcm->out.pos + urb_frames > runtime->buffer_size) {
+ /*
+ The transferred area goes over buffer boundary,
+ copy the data to the temp buffer.
+ */
+ int len;
+
+ len = runtime->buffer_size - line6pcm->out.pos;
+
+ if (len > 0) {
+ memcpy(urb_out->transfer_buffer,
+ runtime->dma_area +
+ line6pcm->out.pos * bytes_per_frame,
+ len * bytes_per_frame);
+ memcpy(urb_out->transfer_buffer +
+ len * bytes_per_frame, runtime->dma_area,
+ (urb_frames - len) * bytes_per_frame);
+ } else
+ dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
+ len);
+ } else {
+ memcpy(urb_out->transfer_buffer,
+ runtime->dma_area +
+ line6pcm->out.pos * bytes_per_frame,
+ urb_out->transfer_buffer_length);
+ }
+
+ line6pcm->out.pos += urb_frames;
+ if (line6pcm->out.pos >= runtime->buffer_size)
+ line6pcm->out.pos -= runtime->buffer_size;
+
+ change_volume(urb_out, line6pcm->volume_playback,
+ bytes_per_frame);
+ } else {
+ memset(urb_out->transfer_buffer, 0,
+ urb_out->transfer_buffer_length);
+ }
+
+ spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING);
+ if (line6pcm->prev_fbuf) {
+ if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) {
+ create_impulse_test_signal(line6pcm, urb_out,
+ bytes_per_frame);
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) {
+ line6_capture_copy(line6pcm,
+ urb_out->transfer_buffer,
+ urb_out->
+ transfer_buffer_length);
+ line6_capture_check_period(line6pcm,
+ urb_out->transfer_buffer_length);
+ }
+ } else {
+ if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON)
+ && line6pcm->out.running && line6pcm->in.running)
+ add_monitor_signal(urb_out, line6pcm->prev_fbuf,
+ line6pcm->volume_monitor,
+ bytes_per_frame);
+ }
+ line6pcm->prev_fbuf = NULL;
+ line6pcm->prev_fsize = 0;
+ }
+ spin_unlock(&line6pcm->in.lock);
+
+ ret = usb_submit_urb(urb_out, GFP_ATOMIC);
+
+ if (ret == 0)
+ set_bit(index, &line6pcm->out.active_urbs);
+ else
+ dev_err(line6pcm->line6->ifcdev,
+ "URB out #%d submission failed (%d)\n", index, ret);
+
+ return 0;
+}
+
+/*
+ Submit all currently available playback URBs.
+ must be called in line6pcm->out.lock context
+ */
+int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ ret = submit_audio_out_urb(line6pcm);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ Callback for completed playback URB.
+*/
+static void audio_out_callback(struct urb *urb)
+{
+ int i, index, length = 0, shutdown = 0;
+ unsigned long flags;
+ struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+ struct snd_pcm_substream *substream =
+ get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
+
+#if USE_CLEAR_BUFFER_WORKAROUND
+ memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+#endif
+
+ line6pcm->out.last_frame = urb->start_frame;
+
+ /* find index of URB */
+ for (index = 0; index < LINE6_ISO_BUFFERS; index++)
+ if (urb == line6pcm->out.urbs[index])
+ break;
+
+ if (index >= LINE6_ISO_BUFFERS)
+ return; /* URB has been unlinked asynchronously */
+
+ for (i = 0; i < LINE6_ISO_PACKETS; i++)
+ length += urb->iso_frame_desc[i].length;
+
+ spin_lock_irqsave(&line6pcm->out.lock, flags);
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ line6pcm->out.pos_done +=
+ length / line6pcm->properties->bytes_per_frame;
+
+ if (line6pcm->out.pos_done >= runtime->buffer_size)
+ line6pcm->out.pos_done -= runtime->buffer_size;
+ }
+
+ clear_bit(index, &line6pcm->out.active_urbs);
+
+ for (i = 0; i < LINE6_ISO_PACKETS; i++)
+ if (urb->iso_frame_desc[i].status == -EXDEV) {
+ shutdown = 1;
+ break;
+ }
+
+ if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs))
+ shutdown = 1;
+
+ if (!shutdown) {
+ submit_audio_out_urb(line6pcm);
+
+ if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) {
+ line6pcm->out.bytes += length;
+ if (line6pcm->out.bytes >= line6pcm->out.period) {
+ line6pcm->out.bytes %= line6pcm->out.period;
+ spin_unlock(&line6pcm->out.lock);
+ snd_pcm_period_elapsed(substream);
+ spin_lock(&line6pcm->out.lock);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&line6pcm->out.lock, flags);
+}
+
+/* open playback callback */
+static int snd_line6_playback_open(struct snd_pcm_substream *substream)
+{
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+ err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &line6pcm->properties->rates);
+ if (err < 0)
+ return err;
+
+ runtime->hw = line6pcm->properties->playback_hw;
+ return 0;
+}
+
+/* close playback callback */
+static int snd_line6_playback_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/* playback operators */
+struct snd_pcm_ops snd_line6_playback_ops = {
+ .open = snd_line6_playback_open,
+ .close = snd_line6_playback_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_line6_hw_params,
+ .hw_free = snd_line6_hw_free,
+ .prepare = snd_line6_prepare,
+ .trigger = snd_line6_trigger,
+ .pointer = snd_line6_pointer,
+};
+
+int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+ struct usb_line6 *line6 = line6pcm->line6;
+ int i;
+
+ /* create audio URBs and fill in constant values: */
+ for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+ struct urb *urb;
+
+ /* URB for audio out: */
+ urb = line6pcm->out.urbs[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+
+ if (urb == NULL)
+ return -ENOMEM;
+
+ urb->dev = line6->usbdev;
+ urb->pipe =
+ usb_sndisocpipe(line6->usbdev,
+ line6->properties->ep_audio_w &
+ USB_ENDPOINT_NUMBER_MASK);
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->start_frame = -1;
+ urb->number_of_packets = LINE6_ISO_PACKETS;
+ urb->interval = LINE6_ISO_INTERVAL;
+ urb->error_count = 0;
+ urb->complete = audio_out_callback;
+ }
+
+ return 0;
+}
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h
new file mode 100644
index 000000000000..51fce29e8726
--- /dev/null
+++ b/sound/usb/line6/playback.h
@@ -0,0 +1,35 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#ifndef PLAYBACK_H
+#define PLAYBACK_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/*
+ * When the TonePort is used with jack in full duplex mode and the outputs are
+ * not connected, the software monitor produces an ugly noise since everything
+ * written to the output buffer (i.e., the input signal) will be repeated in
+ * the next period (sounds like a delay effect). As a workaround, the output
+ * buffer is cleared after the data have been read, but there must be a better
+ * solution. Until one is found, this workaround can be used to fix the
+ * problem.
+ */
+#define USE_CLEAR_BUFFER_WORKAROUND 1
+
+extern struct snd_pcm_ops snd_line6_playback_ops;
+
+extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
+
+#endif
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
new file mode 100644
index 000000000000..daf81d169a42
--- /dev/null
+++ b/sound/usb/line6/pod.c
@@ -0,0 +1,584 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+/*
+ Locate name in binary program dump
+*/
+#define POD_NAME_OFFSET 0
+#define POD_NAME_LENGTH 16
+
+/*
+ Other constants
+*/
+#define POD_CONTROL_SIZE 0x80
+#define POD_BUFSIZE_DUMPREQ 7
+#define POD_STARTUP_DELAY 1000
+
+/*
+ Stages of POD startup procedure
+*/
+enum {
+ POD_STARTUP_INIT = 1,
+ POD_STARTUP_VERSIONREQ,
+ POD_STARTUP_WORKQUEUE,
+ POD_STARTUP_SETUP,
+ POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+};
+
+enum {
+ LINE6_BASSPODXT,
+ LINE6_BASSPODXTLIVE,
+ LINE6_BASSPODXTPRO,
+ LINE6_POCKETPOD,
+ LINE6_PODXT,
+ LINE6_PODXTLIVE_POD,
+ LINE6_PODXTPRO,
+};
+
+struct usb_line6_pod {
+ /* Generic Line 6 USB data */
+ struct usb_line6 line6;
+
+ /* Instrument monitor level */
+ int monitor_level;
+
+ /* Timer for device initialization */
+ struct timer_list startup_timer;
+
+ /* Work handler for device initialization */
+ struct work_struct startup_work;
+
+ /* Current progress in startup procedure */
+ int startup_progress;
+
+ /* Serial number of device */
+ u32 serial_number;
+
+ /* Firmware version (x 100) */
+ int firmware_version;
+
+ /* Device ID */
+ int device_id;
+};
+
+#define POD_SYSEX_CODE 3
+#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+
+/* *INDENT-OFF* */
+
+enum {
+ POD_SYSEX_SAVE = 0x24,
+ POD_SYSEX_SYSTEM = 0x56,
+ POD_SYSEX_SYSTEMREQ = 0x57,
+ /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
+ POD_SYSEX_STORE = 0x71,
+ POD_SYSEX_FINISH = 0x72,
+ POD_SYSEX_DUMPMEM = 0x73,
+ POD_SYSEX_DUMP = 0x74,
+ POD_SYSEX_DUMPREQ = 0x75
+
+ /* dumps entire internal memory of PODxt Pro */
+ /* POD_SYSEX_DUMPMEM2 = 0x76 */
+};
+
+enum {
+ POD_MONITOR_LEVEL = 0x04,
+ POD_SYSTEM_INVALID = 0x10000
+};
+
+/* *INDENT-ON* */
+
+enum {
+ POD_DUMP_MEMORY = 2
+};
+
+enum {
+ POD_BUSY_READ,
+ POD_BUSY_WRITE,
+ POD_CHANNEL_DIRTY,
+ POD_SAVE_PRESSED,
+ POD_BUSY_MIDISEND
+};
+
+static struct snd_ratden pod_ratden = {
+ .num_min = 78125,
+ .num_max = 78125,
+ .num_step = 1,
+ .den = 2
+};
+
+static struct line6_pcm_properties pod_pcm_properties = {
+ .playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .rates = {
+ .nrats = 1,
+ .rats = &pod_ratden},
+ .bytes_per_frame = POD_BYTES_PER_FRAME
+};
+
+static const char pod_version_header[] = {
+ 0xf2, 0x7e, 0x7f, 0x06, 0x02
+};
+
+/* forward declarations: */
+static void pod_startup2(unsigned long data);
+static void pod_startup3(struct usb_line6_pod *pod);
+
+static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
+ int size)
+{
+ return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
+ size);
+}
+
+/*
+ Process a completely received message.
+*/
+static void line6_pod_process_message(struct usb_line6 *line6)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+ const unsigned char *buf = pod->line6.buffer_message;
+
+ if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
+ pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
+ pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
+ (int) buf[10];
+ pod_startup3(pod);
+ return;
+ }
+
+ /* Only look for sysex messages from this device */
+ if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
+ buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
+ return;
+ }
+ if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
+ return;
+
+ if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
+ short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
+ ((int)buf[9] << 4) | (int)buf[10];
+ pod->monitor_level = value;
+ }
+}
+
+/*
+ Send system parameter (from integer).
+*/
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+ int code)
+{
+ char *sysex;
+ static const int size = 5;
+
+ sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
+ if (!sysex)
+ return -ENOMEM;
+ sysex[SYSEX_DATA_OFS] = code;
+ sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
+ line6_send_sysex_message(&pod->line6, sysex, size);
+ kfree(sysex);
+ return 0;
+}
+
+/*
+ "read" request on "serial_number" special file.
+*/
+static ssize_t serial_number_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%u\n", pod->serial_number);
+}
+
+/*
+ "read" request on "firmware_version" special file.
+*/
+static ssize_t firmware_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
+ pod->firmware_version % 100);
+}
+
+/*
+ "read" request on "device_id" special file.
+*/
+static ssize_t device_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *interface = to_usb_interface(dev);
+ struct usb_line6_pod *pod = usb_get_intfdata(interface);
+
+ return sprintf(buf, "%d\n", pod->device_id);
+}
+
+/*
+ POD startup procedure.
+ This is a sequence of functions with special requirements (e.g., must
+ not run immediately after initialization, must not run in interrupt
+ context). After the last one has finished, the device is ready to use.
+*/
+
+static void pod_startup1(struct usb_line6_pod *pod)
+{
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+ (unsigned long)pod);
+}
+
+static void pod_startup2(unsigned long data)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
+ struct usb_line6 *line6 = &pod->line6;
+
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
+
+ /* request firmware version: */
+ line6_version_request_async(line6);
+}
+
+static void pod_startup3(struct usb_line6_pod *pod)
+{
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
+
+ /* schedule work for global work queue: */
+ schedule_work(&pod->startup_work);
+}
+
+static void pod_startup4(struct work_struct *work)
+{
+ struct usb_line6_pod *pod =
+ container_of(work, struct usb_line6_pod, startup_work);
+ struct usb_line6 *line6 = &pod->line6;
+
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
+
+ /* serial number: */
+ line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+ /* ALSA audio interface: */
+ snd_card_register(line6->card);
+}
+
+/* POD special files: */
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
+
+static struct attribute *pod_dev_attrs[] = {
+ &dev_attr_device_id.attr,
+ &dev_attr_firmware_version.attr,
+ &dev_attr_serial_number.attr,
+ NULL
+};
+
+static const struct attribute_group pod_dev_attr_group = {
+ .name = "pod",
+ .attrs = pod_dev_attrs,
+};
+
+/* control info callback */
+static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 65535;
+ return 0;
+}
+
+/* control get callback */
+static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+ ucontrol->value.integer.value[0] = pod->monitor_level;
+ return 0;
+}
+
+/* control put callback */
+static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+ if (ucontrol->value.integer.value[0] == pod->monitor_level)
+ return 0;
+
+ pod->monitor_level = ucontrol->value.integer.value[0];
+ pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
+ POD_MONITOR_LEVEL);
+ return 1;
+}
+
+/* control definition */
+static struct snd_kcontrol_new pod_control_monitor = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitor Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_pod_control_monitor_info,
+ .get = snd_pod_control_monitor_get,
+ .put = snd_pod_control_monitor_put
+};
+
+/*
+ POD device disconnected.
+*/
+static void line6_pod_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)line6;
+
+ del_timer_sync(&pod->startup_timer);
+ cancel_work_sync(&pod->startup_work);
+}
+
+/*
+ Try to init POD device.
+*/
+static int pod_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+ struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+
+ line6->process_message = line6_pod_process_message;
+ line6->disconnect = line6_pod_disconnect;
+
+ init_timer(&pod->startup_timer);
+ INIT_WORK(&pod->startup_work, pod_startup4);
+
+ /* create sysfs entries: */
+ err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group);
+ if (err < 0)
+ return err;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(line6);
+ if (err < 0)
+ return err;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &pod_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register monitor control: */
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
+ if (err < 0)
+ return err;
+
+ /*
+ When the sound card is registered at this point, the PODxt Live
+ displays "Invalid Code Error 07", so we do it later in the event
+ handler.
+ */
+
+ if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
+ pod->monitor_level = POD_SYSTEM_INVALID;
+
+ /* initiate startup procedure: */
+ pod_startup1(pod);
+ }
+
+ return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id pod_id_table[] = {
+ { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT },
+ { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE },
+ { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO },
+ { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
+ { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT },
+ { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
+ { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, pod_id_table);
+
+static const struct line6_properties pod_properties_table[] = {
+ [LINE6_BASSPODXT] = {
+ .id = "BassPODxt",
+ .name = "BassPODxt",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_BASSPODXTLIVE] = {
+ .id = "BassPODxtLive",
+ .name = "BassPODxt Live",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_BASSPODXTPRO] = {
+ .id = "BassPODxtPro",
+ .name = "BassPODxt Pro",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_POCKETPOD] = {
+ .id = "PocketPOD",
+ .name = "Pocket POD",
+ .capabilities = LINE6_CAP_CONTROL,
+ .altsetting = 0,
+ .ep_ctrl_r = 0x82,
+ .ep_ctrl_w = 0x02,
+ /* no audio channel */
+ },
+ [LINE6_PODXT] = {
+ .id = "PODxt",
+ .name = "PODxt",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODXTLIVE_POD] = {
+ .id = "PODxtLive",
+ .name = "PODxt Live",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODXTPRO] = {
+ .id = "PODxtPro",
+ .name = "PODxt Pro",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int pod_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id, "Line6-POD",
+ &pod_properties_table[id->driver_info],
+ pod_init, sizeof(struct usb_line6_pod));
+}
+
+static struct usb_driver pod_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = pod_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = pod_id_table,
+};
+
+module_usb_driver(pod_driver);
+
+MODULE_DESCRIPTION("Line 6 POD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
new file mode 100644
index 000000000000..63dcaef41ac3
--- /dev/null
+++ b/sound/usb/line6/podhd.c
@@ -0,0 +1,192 @@
+/*
+ * Line 6 Pod HD
+ *
+ * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.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, version 2.
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+enum {
+ LINE6_PODHD300,
+ LINE6_PODHD400,
+ LINE6_PODHD500_0,
+ LINE6_PODHD500_1,
+};
+
+#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+
+static struct snd_ratden podhd_ratden = {
+ .num_min = 48000,
+ .num_max = 48000,
+ .num_step = 1,
+ .den = 1,
+};
+
+static struct line6_pcm_properties podhd_pcm_properties = {
+ .playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .rates = {
+ .nrats = 1,
+ .rats = &podhd_ratden},
+ .bytes_per_frame = PODHD_BYTES_PER_FRAME
+};
+
+/*
+ Try to init POD HD device.
+*/
+static int podhd_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(line6);
+ if (err < 0)
+ return err;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &podhd_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register USB audio system: */
+ return snd_card_register(line6->card);
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id podhd_id_table[] = {
+ { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
+ { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
+ { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
+ { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, podhd_id_table);
+
+static const struct line6_properties podhd_properties_table[] = {
+ [LINE6_PODHD300] = {
+ .id = "PODHD300",
+ .name = "POD HD300",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODHD400] = {
+ .id = "PODHD400",
+ .name = "POD HD400",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 5,
+ .ep_ctrl_r = 0x84,
+ .ep_ctrl_w = 0x03,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODHD500_0] = {
+ .id = "PODHD500",
+ .name = "POD HD500",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x81,
+ .ep_ctrl_w = 0x01,
+ .ep_audio_r = 0x86,
+ .ep_audio_w = 0x02,
+ },
+ [LINE6_PODHD500_1] = {
+ .id = "PODHD500",
+ .name = "POD HD500",
+ .capabilities = LINE6_CAP_CONTROL
+ | LINE6_CAP_PCM
+ | LINE6_CAP_HWMON,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x81,
+ .ep_ctrl_w = 0x01,
+ .ep_audio_r = 0x86,
+ .ep_audio_w = 0x02,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int podhd_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id, "Line6-PODHD",
+ &podhd_properties_table[id->driver_info],
+ podhd_init, sizeof(struct usb_line6));
+}
+
+static struct usb_driver podhd_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = podhd_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = podhd_id_table,
+};
+
+module_usb_driver(podhd_driver);
+
+MODULE_DESCRIPTION("Line 6 PODHD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
new file mode 100644
index 000000000000..6d4c50c9b17d
--- /dev/null
+++ b/sound/usb/line6/toneport.c
@@ -0,0 +1,580 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ * Emil Myhrman (emil.myhrman@gmail.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, version 2.
+ *
+ */
+
+#include <linux/wait.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+
+enum line6_device_type {
+ LINE6_GUITARPORT,
+ LINE6_PODSTUDIO_GX,
+ LINE6_PODSTUDIO_UX1,
+ LINE6_PODSTUDIO_UX2,
+ LINE6_TONEPORT_GX,
+ LINE6_TONEPORT_UX1,
+ LINE6_TONEPORT_UX2,
+};
+
+struct usb_line6_toneport;
+
+struct toneport_led {
+ struct led_classdev dev;
+ char name[64];
+ struct usb_line6_toneport *toneport;
+ bool registered;
+};
+
+struct usb_line6_toneport {
+ /* Generic Line 6 USB data */
+ struct usb_line6 line6;
+
+ /* Source selector */
+ int source;
+
+ /* Serial number of device */
+ u32 serial_number;
+
+ /* Firmware version (x 100) */
+ u8 firmware_version;
+
+ /* Timer for delayed PCM startup */
+ struct timer_list timer;
+
+ /* Device type */
+ enum line6_device_type type;
+
+ /* LED instances */
+ struct toneport_led leds[2];
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
+
+#define TONEPORT_PCM_DELAY 1
+
+static struct snd_ratden toneport_ratden = {
+ .num_min = 44100,
+ .num_max = 44100,
+ .num_step = 1,
+ .den = 1
+};
+
+static struct line6_pcm_properties toneport_pcm_properties = {
+ .playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .rates = {
+ .nrats = 1,
+ .rats = &toneport_ratden},
+ .bytes_per_frame = 4
+};
+
+static const struct {
+ const char *name;
+ int code;
+} toneport_source_info[] = {
+ {"Microphone", 0x0a01},
+ {"Line", 0x0801},
+ {"Instrument", 0x0b01},
+ {"Inst & Mic", 0x0901}
+};
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
+{
+ int ret;
+
+ ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
+
+ if (ret < 0) {
+ dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* monitor info callback */
+static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 256;
+ return 0;
+}
+
+/* monitor get callback */
+static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
+ return 0;
+}
+
+/* monitor put callback */
+static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ int err;
+
+ if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
+ return 0;
+
+ line6pcm->volume_monitor = ucontrol->value.integer.value[0];
+
+ if (line6pcm->volume_monitor > 0) {
+ err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR);
+ if (err < 0) {
+ line6pcm->volume_monitor = 0;
+ line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+ return err;
+ }
+ } else {
+ line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
+ }
+
+ return 1;
+}
+
+/* source info callback */
+static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const int size = ARRAY_SIZE(toneport_source_info);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = size;
+
+ if (uinfo->value.enumerated.item >= size)
+ uinfo->value.enumerated.item = size - 1;
+
+ strcpy(uinfo->value.enumerated.name,
+ toneport_source_info[uinfo->value.enumerated.item].name);
+
+ return 0;
+}
+
+/* source get callback */
+static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6pcm->line6;
+ ucontrol->value.enumerated.item[0] = toneport->source;
+ return 0;
+}
+
+/* source put callback */
+static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6pcm->line6;
+ unsigned int source;
+
+ source = ucontrol->value.enumerated.item[0];
+ if (source >= ARRAY_SIZE(toneport_source_info))
+ return -EINVAL;
+ if (source == toneport->source)
+ return 0;
+
+ toneport->source = source;
+ toneport_send_cmd(toneport->line6.usbdev,
+ toneport_source_info[source].code, 0x0000);
+ return 1;
+}
+
+static void toneport_start_pcm(unsigned long arg)
+{
+ struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
+ struct usb_line6 *line6 = &toneport->line6;
+
+ line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR);
+}
+
+/* control definition */
+static struct snd_kcontrol_new toneport_control_monitor = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Monitor Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_toneport_monitor_info,
+ .get = snd_toneport_monitor_get,
+ .put = snd_toneport_monitor_put
+};
+
+/* source selector definition */
+static struct snd_kcontrol_new toneport_control_source = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Capture Source",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_toneport_source_info,
+ .get = snd_toneport_source_get,
+ .put = snd_toneport_source_put
+};
+
+/*
+ For the led on Guitarport.
+ Brightness goes from 0x00 to 0x26. Set a value above this to have led
+ blink.
+ (void cmd_0x02(byte red, byte green)
+*/
+
+static bool toneport_has_led(struct usb_line6_toneport *toneport)
+{
+ switch (toneport->type) {
+ case LINE6_GUITARPORT:
+ case LINE6_TONEPORT_GX:
+ /* add your device here if you are missing support for the LEDs */
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static const char * const led_colors[2] = { "red", "green" };
+static const int led_init_vals[2] = { 0x00, 0x26 };
+
+static void toneport_update_led(struct usb_line6_toneport *toneport)
+{
+ toneport_send_cmd(toneport->line6.usbdev,
+ (toneport->leds[0].dev.brightness << 8) | 0x0002,
+ toneport->leds[1].dev.brightness);
+}
+
+static void toneport_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct toneport_led *leds =
+ container_of(led_cdev, struct toneport_led, dev);
+ toneport_update_led(leds->toneport);
+}
+
+static int toneport_init_leds(struct usb_line6_toneport *toneport)
+{
+ struct device *dev = &toneport->line6.usbdev->dev;
+ int i, err;
+
+ for (i = 0; i < 2; i++) {
+ struct toneport_led *led = &toneport->leds[i];
+ struct led_classdev *leddev = &led->dev;
+
+ led->toneport = toneport;
+ snprintf(led->name, sizeof(led->name), "%s::%s",
+ dev_name(dev), led_colors[i]);
+ leddev->name = led->name;
+ leddev->brightness = led_init_vals[i];
+ leddev->max_brightness = 0x26;
+ leddev->brightness_set = toneport_led_brightness_set;
+ err = led_classdev_register(dev, leddev);
+ if (err)
+ return err;
+ led->registered = true;
+ }
+
+ return 0;
+}
+
+static void toneport_remove_leds(struct usb_line6_toneport *toneport)
+{
+ struct toneport_led *led;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ led = &toneport->leds[i];
+ if (!led->registered)
+ break;
+ led_classdev_unregister(&led->dev);
+ led->registered = false;
+ }
+}
+
+static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
+{
+ switch (toneport->type) {
+ case LINE6_TONEPORT_UX1:
+ case LINE6_TONEPORT_UX2:
+ case LINE6_PODSTUDIO_UX1:
+ case LINE6_PODSTUDIO_UX2:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*
+ Setup Toneport device.
+*/
+static void toneport_setup(struct usb_line6_toneport *toneport)
+{
+ int ticks;
+ struct usb_line6 *line6 = &toneport->line6;
+ struct usb_device *usbdev = line6->usbdev;
+
+ /* sync time on device with host: */
+ ticks = (int)get_seconds();
+ line6_write_data(line6, 0x80c6, &ticks, 4);
+
+ /* enable device: */
+ toneport_send_cmd(usbdev, 0x0301, 0x0000);
+
+ /* initialize source select: */
+ if (toneport_has_source_select(toneport))
+ toneport_send_cmd(usbdev,
+ toneport_source_info[toneport->source].code,
+ 0x0000);
+
+ if (toneport_has_led(toneport))
+ toneport_update_led(toneport);
+
+ mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
+}
+
+/*
+ Toneport device disconnected.
+*/
+static void line6_toneport_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_toneport *toneport =
+ (struct usb_line6_toneport *)line6;
+
+ del_timer_sync(&toneport->timer);
+
+ if (toneport_has_led(toneport))
+ toneport_remove_leds(toneport);
+}
+
+
+/*
+ Try to init Toneport device.
+*/
+static int toneport_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ int err;
+ struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
+
+ toneport->type = id->driver_info;
+ setup_timer(&toneport->timer, toneport_start_pcm,
+ (unsigned long)toneport);
+
+ line6->disconnect = line6_toneport_disconnect;
+
+ /* initialize PCM subsystem: */
+ err = line6_init_pcm(line6, &toneport_pcm_properties);
+ if (err < 0)
+ return err;
+
+ /* register monitor control: */
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&toneport_control_monitor,
+ line6->line6pcm));
+ if (err < 0)
+ return err;
+
+ /* register source select control: */
+ if (toneport_has_source_select(toneport)) {
+ err =
+ snd_ctl_add(line6->card,
+ snd_ctl_new1(&toneport_control_source,
+ line6->line6pcm));
+ if (err < 0)
+ return err;
+ }
+
+ line6_read_serial_number(line6, &toneport->serial_number);
+ line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
+
+ if (toneport_has_led(toneport)) {
+ err = toneport_init_leds(toneport);
+ if (err < 0)
+ return err;
+ }
+
+ toneport_setup(toneport);
+
+ /* register audio system: */
+ return snd_card_register(line6->card);
+}
+
+#ifdef CONFIG_PM
+/*
+ Resume Toneport device after reset.
+*/
+static int toneport_reset_resume(struct usb_interface *interface)
+{
+ toneport_setup(usb_get_intfdata(interface));
+ return line6_resume(interface);
+}
+#endif
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id toneport_id_table[] = {
+ { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT },
+ { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX },
+ { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 },
+ { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
+ { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX },
+ { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 },
+ { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, toneport_id_table);
+
+static const struct line6_properties toneport_properties_table[] = {
+ [LINE6_GUITARPORT] = {
+ .id = "GuitarPort",
+ .name = "GuitarPort",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_GX] = {
+ .id = "PODStudioGX",
+ .name = "POD Studio GX",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_UX1] = {
+ .id = "PODStudioUX1",
+ .name = "POD Studio UX1",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_PODSTUDIO_UX2] = {
+ .id = "PODStudioUX2",
+ .name = "POD Studio UX2",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_GX] = {
+ .id = "TonePortGX",
+ .name = "TonePort GX",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_UX1] = {
+ .id = "TonePortUX1",
+ .name = "TonePort UX1",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* 1..4 seem to be ok */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_TONEPORT_UX2] = {
+ .id = "TonePortUX2",
+ .name = "TonePort UX2",
+ .capabilities = LINE6_CAP_PCM,
+ .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
+ /* no control channel */
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+};
+
+/*
+ Probe USB device.
+*/
+static int toneport_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id, "Line6-TonePort",
+ &toneport_properties_table[id->driver_info],
+ toneport_init, sizeof(struct usb_line6_toneport));
+}
+
+static struct usb_driver toneport_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = toneport_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = toneport_reset_resume,
+#endif
+ .id_table = toneport_id_table,
+};
+
+module_usb_driver(toneport_driver);
+
+MODULE_DESCRIPTION("TonePort USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c
new file mode 100644
index 000000000000..ddc23ddf0750
--- /dev/null
+++ b/sound/usb/line6/variax.c
@@ -0,0 +1,306 @@
+/*
+ * Line 6 Linux USB driver
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
+
+#include "driver.h"
+
+#define VARIAX_STARTUP_DELAY1 1000
+#define VARIAX_STARTUP_DELAY3 100
+#define VARIAX_STARTUP_DELAY4 100
+
+/*
+ Stages of Variax startup procedure
+*/
+enum {
+ VARIAX_STARTUP_INIT = 1,
+ VARIAX_STARTUP_VERSIONREQ,
+ VARIAX_STARTUP_WAIT,
+ VARIAX_STARTUP_ACTIVATE,
+ VARIAX_STARTUP_WORKQUEUE,
+ VARIAX_STARTUP_SETUP,
+ VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
+};
+
+enum {
+ LINE6_PODXTLIVE_VARIAX,
+ LINE6_VARIAX
+};
+
+struct usb_line6_variax {
+ /* Generic Line 6 USB data */
+ struct usb_line6 line6;
+
+ /* Buffer for activation code */
+ unsigned char *buffer_activate;
+
+ /* Handler for device initialization */
+ struct work_struct startup_work;
+
+ /* Timers for device initialization */
+ struct timer_list startup_timer1;
+ struct timer_list startup_timer2;
+
+ /* Current progress in startup procedure */
+ int startup_progress;
+};
+
+#define VARIAX_OFFSET_ACTIVATE 7
+
+/*
+ This message is sent by the device during initialization and identifies
+ the connected guitar version.
+*/
+static const char variax_init_version[] = {
+ 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
+ 0x07, 0x00, 0x00, 0x00
+};
+
+/*
+ This message is the last one sent by the device during initialization.
+*/
+static const char variax_init_done[] = {
+ 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
+};
+
+static const char variax_activate[] = {
+ 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
+ 0xf7
+};
+
+/* forward declarations: */
+static void variax_startup2(unsigned long data);
+static void variax_startup4(unsigned long data);
+static void variax_startup5(unsigned long data);
+
+static void variax_activate_async(struct usb_line6_variax *variax, int a)
+{
+ variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
+ line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
+ sizeof(variax_activate));
+}
+
+/*
+ Variax startup procedure.
+ This is a sequence of functions with special requirements (e.g., must
+ not run immediately after initialization, must not run in interrupt
+ context). After the last one has finished, the device is ready to use.
+*/
+
+static void variax_startup1(struct usb_line6_variax *variax)
+{
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
+}
+
+static void variax_startup2(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+ struct usb_line6 *line6 = &variax->line6;
+
+ /* schedule another startup procedure until startup is complete: */
+ if (variax->startup_progress >= VARIAX_STARTUP_LAST)
+ return;
+
+ variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
+
+ /* request firmware version: */
+ line6_version_request_async(line6);
+}
+
+static void variax_startup3(struct usb_line6_variax *variax)
+{
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
+
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
+ variax_startup4, (unsigned long)variax);
+}
+
+static void variax_startup4(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_ACTIVATE);
+
+ /* activate device: */
+ variax_activate_async(variax, 1);
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
+ variax_startup5, (unsigned long)variax);
+}
+
+static void variax_startup5(unsigned long data)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_WORKQUEUE);
+
+ /* schedule work for global work queue: */
+ schedule_work(&variax->startup_work);
+}
+
+static void variax_startup6(struct work_struct *work)
+{
+ struct usb_line6_variax *variax =
+ container_of(work, struct usb_line6_variax, startup_work);
+
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
+
+ /* ALSA audio interface: */
+ snd_card_register(variax->line6.card);
+}
+
+/*
+ Process a completely received message.
+*/
+static void line6_variax_process_message(struct usb_line6 *line6)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ const unsigned char *buf = variax->line6.buffer_message;
+
+ switch (buf[0]) {
+ case LINE6_RESET:
+ dev_info(variax->line6.ifcdev, "VARIAX reset\n");
+ break;
+
+ case LINE6_SYSEX_BEGIN:
+ if (memcmp(buf + 1, variax_init_version + 1,
+ sizeof(variax_init_version) - 1) == 0) {
+ variax_startup3(variax);
+ } else if (memcmp(buf + 1, variax_init_done + 1,
+ sizeof(variax_init_done) - 1) == 0) {
+ /* notify of complete initialization: */
+ variax_startup4((unsigned long)variax);
+ }
+ break;
+ }
+}
+
+/*
+ Variax destructor.
+*/
+static void line6_variax_disconnect(struct usb_line6 *line6)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
+
+ del_timer(&variax->startup_timer1);
+ del_timer(&variax->startup_timer2);
+ cancel_work_sync(&variax->startup_work);
+
+ kfree(variax->buffer_activate);
+}
+
+/*
+ Try to init workbench device.
+*/
+static int variax_init(struct usb_line6 *line6,
+ const struct usb_device_id *id)
+{
+ struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+ int err;
+
+ line6->process_message = line6_variax_process_message;
+ line6->disconnect = line6_variax_disconnect;
+
+ init_timer(&variax->startup_timer1);
+ init_timer(&variax->startup_timer2);
+ INIT_WORK(&variax->startup_work, variax_startup6);
+
+ /* initialize USB buffers: */
+ variax->buffer_activate = kmemdup(variax_activate,
+ sizeof(variax_activate), GFP_KERNEL);
+
+ if (variax->buffer_activate == NULL)
+ return -ENOMEM;
+
+ /* initialize MIDI subsystem: */
+ err = line6_init_midi(&variax->line6);
+ if (err < 0)
+ return err;
+
+ /* initiate startup procedure: */
+ variax_startup1(variax);
+ return 0;
+}
+
+#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
+#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
+
+/* table of devices that work with this driver */
+static const struct usb_device_id variax_id_table[] = {
+ { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
+ { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, variax_id_table);
+
+static const struct line6_properties variax_properties_table[] = {
+ [LINE6_PODXTLIVE_VARIAX] = {
+ .id = "PODxtLive",
+ .name = "PODxt Live",
+ .capabilities = LINE6_CAP_CONTROL,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x86,
+ .ep_ctrl_w = 0x05,
+ .ep_audio_r = 0x82,
+ .ep_audio_w = 0x01,
+ },
+ [LINE6_VARIAX] = {
+ .id = "Variax",
+ .name = "Variax Workbench",
+ .capabilities = LINE6_CAP_CONTROL,
+ .altsetting = 1,
+ .ep_ctrl_r = 0x82,
+ .ep_ctrl_w = 0x01,
+ /* no audio channel */
+ }
+};
+
+/*
+ Probe USB device.
+*/
+static int variax_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ return line6_probe(interface, id, "Line6-Variax",
+ &variax_properties_table[id->driver_info],
+ variax_init, sizeof(struct usb_line6_variax));
+}
+
+static struct usb_driver variax_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = variax_probe,
+ .disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+ .suspend = line6_suspend,
+ .resume = line6_resume,
+ .reset_resume = line6_resume,
+#endif
+ .id_table = variax_id_table,
+};
+
+module_usb_driver(variax_driver);
+
+MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 5bfb695547f8..417ebb11cf48 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -2292,14 +2292,13 @@ int snd_usbmidi_create(struct snd_card *card,
umidi->iface = iface;
umidi->quirk = quirk;
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
- init_timer(&umidi->error_timer);
spin_lock_init(&umidi->disc_lock);
init_rwsem(&umidi->disc_rwsem);
mutex_init(&umidi->mutex);
umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
le16_to_cpu(umidi->dev->descriptor.idProduct));
- umidi->error_timer.function = snd_usbmidi_error_timer;
- umidi->error_timer.data = (unsigned long)umidi;
+ setup_timer(&umidi->error_timer, snd_usbmidi_error_timer,
+ (unsigned long)umidi);
/* detect the endpoint(s) to use */
memset(endpoints, 0, sizeof(endpoints));
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0d8aba5fe1a8..b4ef410e5a98 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1464,6 +1464,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
subs->last_frame_number = usb_get_current_frame_number(subs->dev);
subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
+ if (subs->trigger_tstamp_pending_update) {
+ /* this is the first actual URB submitted,
+ * update trigger timestamp to reflect actual start time
+ */
+ snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
+ subs->trigger_tstamp_pending_update = false;
+ }
+
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = bytes;
if (period_elapsed)
@@ -1550,6 +1558,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ subs->trigger_tstamp_pending_update = true;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
subs->data_endpoint->retire_data_urb = retire_playback_urb;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 0a598af9b38b..67d476548dcf 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2486,6 +2486,28 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+{
+ /* Akai MPC Element */
+ USB_DEVICE(0x09e8, 0x0021),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = & (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
/* TerraTec devices */
{
USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012),
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index a7398412310b..753a47de8459 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1111,6 +1111,11 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
+bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
+{
+ /* MS Lifecam HD-5000 doesn't support reading the sample rate. */
+ return chip->usb_id == USB_ID(0x045E, 0x076D);
+}
/* Marantz/Denon USB DACs need a vendor cmd to switch
* between PCM and native DSD mode
@@ -1122,6 +1127,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
int err;
switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
@@ -1201,6 +1207,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) {
switch (le16_to_cpu(dev->descriptor.idProduct)) {
+ case 0x1003: /* Denon DA300-USB */
case 0x3005: /* Marantz HD-DAC1 */
case 0x3006: /* Marantz SA-14S1 */
mdelay(20);
@@ -1262,6 +1269,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
/* Denon/Marantz devices with USB DAC functionality */
switch (chip->usb_id) {
+ case USB_ID(0x154e, 0x1003): /* Denon DA300-USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
if (fp->altsetting == 2)
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 1b862386577d..2cd71ed1201f 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -21,6 +21,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
struct audioformat *fmt);
+bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip);
+
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
struct audioformat *fp);
diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h
index 4dd74ab1e9cc..90369001eab6 100644
--- a/sound/usb/usx2y/usb_stream.h
+++ b/sound/usb/usx2y/usb_stream.h
@@ -1,76 +1,7 @@
-/*
- * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
- *
- * 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.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+#ifndef __USB_STREAM_H
+#define __USB_STREAM_H
-#define USB_STREAM_INTERFACE_VERSION 2
-
-#define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \
- _IOW('H', 0x90, struct usb_stream_config)
-
-struct usb_stream_packet {
- unsigned offset;
- unsigned length;
-};
-
-
-struct usb_stream_config {
- unsigned version;
- unsigned sample_rate;
- unsigned period_frames;
- unsigned frame_size;
-};
-
-struct usb_stream {
- struct usb_stream_config cfg;
- unsigned read_size;
- unsigned write_size;
-
- int period_size;
-
- unsigned state;
-
- int idle_insize;
- int idle_outsize;
- int sync_packet;
- unsigned insize_done;
- unsigned periods_done;
- unsigned periods_polled;
-
- struct usb_stream_packet outpacket[2];
- unsigned inpackets;
- unsigned inpacket_head;
- unsigned inpacket_split;
- unsigned inpacket_split_at;
- unsigned next_inpacket_split;
- unsigned next_inpacket_split_at;
- struct usb_stream_packet inpacket[0];
-};
-
-enum usb_stream_state {
- usb_stream_invalid,
- usb_stream_stopped,
- usb_stream_sync0,
- usb_stream_sync1,
- usb_stream_ready,
- usb_stream_running,
- usb_stream_xrun,
-};
-
-#if __KERNEL__
+#include <uapi/sound/usb_stream.h>
#define USB_STREAM_NURBS 4
#define USB_STREAM_URBDEPTH 4
@@ -108,5 +39,4 @@ void usb_stream_free(struct usb_stream_kernel *);
int usb_stream_start(struct usb_stream_kernel *);
void usb_stream_stop(struct usb_stream_kernel *);
-
-#endif
+#endif /* __USB_STREAM_H */