summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/arm/Kconfig14
-rw-r--r--sound/arm/Makefile8
-rw-r--r--sound/arm/pxa2xx-ac97.c410
-rw-r--r--sound/arm/pxa2xx-pcm.c367
-rw-r--r--sound/arm/pxa2xx-pcm.h29
-rw-r--r--sound/core/Makefile2
-rw-r--r--sound/core/device.c15
-rw-r--r--sound/core/info.c5
-rw-r--r--sound/core/memalloc.c8
-rw-r--r--sound/core/memory.c10
-rw-r--r--sound/core/oss/pcm_oss.c11
-rw-r--r--sound/core/pcm_compat.c49
-rw-r--r--sound/core/pcm_lib.c20
-rw-r--r--sound/core/pcm_native.c14
-rw-r--r--sound/core/seq/Makefile2
-rw-r--r--sound/core/seq/instr/ainstr_gf1.c3
-rw-r--r--sound/core/seq/instr/ainstr_iw.c8
-rw-r--r--sound/core/seq/oss/seq_oss_device.h6
-rw-r--r--sound/core/seq/seq_memory.c4
-rw-r--r--sound/core/seq/seq_midi.c16
-rw-r--r--sound/core/seq/seq_midi_event.c2
-rw-r--r--sound/core/sound.c2
-rw-r--r--sound/core/sound_oss.c7
-rw-r--r--sound/core/timer.c16
-rw-r--r--sound/core/wrappers.c2
-rw-r--r--sound/drivers/serial-u16550.c10
-rw-r--r--sound/drivers/vx/vx_mixer.c4
-rw-r--r--sound/drivers/vx/vx_pcm.c8
-rw-r--r--sound/drivers/vx/vx_uer.c46
-rw-r--r--sound/i2c/other/ak4114.c1
-rw-r--r--sound/isa/Kconfig2
-rw-r--r--sound/isa/ad1816a/ad1816a.c5
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c14
-rw-r--r--sound/isa/ad1848/ad1848_lib.c1
-rw-r--r--sound/isa/cmi8330.c4
-rw-r--r--sound/isa/cs423x/cs4231_lib.c2
-rw-r--r--sound/isa/gus/gus_io.c6
-rw-r--r--sound/isa/gus/gus_main.c2
-rw-r--r--sound/isa/opl3sa2.c114
-rw-r--r--sound/isa/sb/emu8000_patch.c2
-rw-r--r--sound/isa/sb/sb16_main.c2
-rw-r--r--sound/isa/sb/sb_mixer.c4
-rw-r--r--sound/isa/wavefront/wavefront_fx.c34
-rw-r--r--sound/oss/Kconfig16
-rw-r--r--sound/oss/Makefile2
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c4
-rw-r--r--sound/oss/i810_audio.c4
-rw-r--r--sound/oss/pss.c2
-rw-r--r--sound/oss/vidc.h4
-rw-r--r--sound/pci/Kconfig12
-rw-r--r--sound/pci/ac97/Makefile2
-rw-r--r--sound/pci/ac97/ac97_bus.c79
-rw-r--r--sound/pci/ac97/ac97_codec.c110
-rw-r--r--sound/pci/ac97/ac97_patch.c452
-rw-r--r--sound/pci/ac97/ac97_patch.h1
-rw-r--r--sound/pci/ali5451/ali5451.c10
-rw-r--r--sound/pci/atiixp.c14
-rw-r--r--sound/pci/atiixp_modem.c1
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c10
-rw-r--r--sound/pci/ca0106/ca0106_main.c8
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c4
-rw-r--r--sound/pci/cmipci.c25
-rw-r--r--sound/pci/cs4281.c2
-rw-r--r--sound/pci/cs46xx/cs46xx.c2
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c33
-rw-r--r--sound/pci/emu10k1/emu10k1.c12
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c137
-rw-r--r--sound/pci/emu10k1/emu10k1x.c4
-rw-r--r--sound/pci/emu10k1/emufx.c26
-rw-r--r--sound/pci/emu10k1/emumixer.c23
-rw-r--r--sound/pci/emu10k1/emupcm.c7
-rw-r--r--sound/pci/emu10k1/memory.c2
-rw-r--r--sound/pci/emu10k1/p16v.c20
-rw-r--r--sound/pci/ens1370.c24
-rw-r--r--sound/pci/es1968.c26
-rw-r--r--sound/pci/fm801.c8
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c97
-rw-r--r--sound/pci/hda/hda_codec.h4
-rw-r--r--sound/pci/hda/hda_generic.c5
-rw-r--r--sound/pci/hda/hda_intel.c163
-rw-r--r--sound/pci/hda/hda_patch.h3
-rw-r--r--sound/pci/hda/patch_analog.c4
-rw-r--r--sound/pci/hda/patch_cmedia.c6
-rw-r--r--sound/pci/hda/patch_realtek.c37
-rw-r--r--sound/pci/hda/patch_si3054.c300
-rw-r--r--sound/pci/hda/patch_sigmatel.c812
-rw-r--r--sound/pci/ice1712/delta.c10
-rw-r--r--sound/pci/ice1712/ice1712.c10
-rw-r--r--sound/pci/ice1712/ice1724.c6
-rw-r--r--sound/pci/intel8x0.c80
-rw-r--r--sound/pci/korg1212/korg1212.c4
-rw-r--r--sound/pci/maestro3.c34
-rw-r--r--sound/pci/mixart/mixart.c4
-rw-r--r--sound/pci/nm256/nm256.c107
-rw-r--r--sound/pci/rme32.c4
-rw-r--r--sound/pci/rme96.c4
-rw-r--r--sound/pci/rme9652/hdsp.c119
-rw-r--r--sound/pci/rme9652/hdspm.c33
-rw-r--r--sound/pci/rme9652/rme9652.c26
-rw-r--r--sound/pci/trident/trident_main.c16
-rw-r--r--sound/pci/trident/trident_memory.c2
-rw-r--r--sound/pci/via82xx.c33
-rw-r--r--sound/pci/via82xx_modem.c16
-rw-r--r--sound/pci/vx222/vx222_ops.c4
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c238
-rw-r--r--sound/pcmcia/Kconfig15
-rw-r--r--sound/pcmcia/vx/Makefile7
-rw-r--r--sound/pcmcia/vx/vx_entry.c375
-rw-r--r--sound/pcmcia/vx/vxp440.c14
-rw-r--r--sound/pcmcia/vx/vxp_ops.c2
-rw-r--r--sound/pcmcia/vx/vxpocket.c437
-rw-r--r--sound/pcmcia/vx/vxpocket.h27
-rw-r--r--sound/ppc/awacs.c6
-rw-r--r--sound/ppc/burgundy.c4
-rw-r--r--sound/ppc/pmac.c11
-rw-r--r--sound/ppc/pmac.h5
-rw-r--r--sound/ppc/tumbler.c16
-rw-r--r--sound/sound_core.c27
-rw-r--r--sound/sparc/Kconfig22
-rw-r--r--sound/sparc/Makefile4
-rw-r--r--sound/sparc/dbri.c2729
-rw-r--r--sound/synth/emux/emux_synth.c1
-rw-r--r--sound/usb/usbaudio.c431
-rw-r--r--sound/usb/usbaudio.h38
-rw-r--r--sound/usb/usbmidi.c132
-rw-r--r--sound/usb/usbmixer.c4
-rw-r--r--sound/usb/usbquirks.h29
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c3
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c8
131 files changed, 7077 insertions, 1832 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index ee794ae06040..b65ee4701f98 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -77,7 +77,7 @@ source "sound/parisc/Kconfig"
endmenu
menu "Open Sound System"
- depends on SOUND!=n && (BROKEN || (!SPARC32 && !SPARC64))
+ depends on SOUND!=n
config SOUND_PRIME
tristate "Open Sound System (DEPRECATED)"
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 34c1740aa6e9..2e4a5e0d16db 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -20,5 +20,17 @@ config SND_ARMAACI
select SND_PCM
select SND_AC97_CODEC
-endmenu
+config SND_PXA2XX_PCM
+ tristate
+ select SND_PCM
+
+config SND_PXA2XX_AC97
+ tristate "AC97 driver for the Intel PXA2xx chip"
+ depends on ARCH_PXA && SND
+ select SND_PXA2XX_PCM
+ select SND_AC97_CODEC
+ help
+ Say Y or M if you want to support any AC97 codec attached to
+ the PXA2xx AC97 interface.
+endmenu
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index f74ec28e1068..103f136926d9 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -3,9 +3,11 @@
#
snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
+snd-aaci-objs := aaci.o devdma.o
+snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
+snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
-# Toplevel Module Dependency
obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o
-
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
-snd-aaci-objs := aaci.o devdma.o
+obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
+obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
new file mode 100644
index 000000000000..29450befb5da
--- /dev/null
+++ b/sound/arm/pxa2xx-ac97.c
@@ -0,0 +1,410 @@
+/*
+ * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
+ *
+ * Author: Nicolas Pitre
+ * Created: Dec 02, 2004
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+
+#include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+
+
+static DECLARE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+static unsigned short pxa2xx_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+ unsigned short val = -1;
+ volatile u32 *reg_addr;
+
+ down(&car_mutex);
+ if (CAR & CAR_CAIP) {
+ printk(KERN_CRIT"%s: CAR_CAIP already set\n", __FUNCTION__);
+ goto out;
+ }
+
+ /* set up primary or secondary codec space */
+ reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
+ reg_addr += (reg >> 1);
+
+ /* start read access across the ac97 link */
+ gsr_bits = 0;
+ val = *reg_addr;
+ if (reg == AC97_GPIO_STATUS)
+ goto out;
+ wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1);
+ if (!gsr_bits & GSR_SDONE) {
+ printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
+ __FUNCTION__, reg, gsr_bits);
+ val = -1;
+ goto out;
+ }
+
+ /* valid data now */
+ gsr_bits = 0;
+ val = *reg_addr;
+ /* but we've just started another cycle... */
+ wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1);
+
+out: up(&car_mutex);
+ return val;
+}
+
+static void pxa2xx_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+ volatile u32 *reg_addr;
+
+ down(&car_mutex);
+
+ if (CAR & CAR_CAIP) {
+ printk(KERN_CRIT "%s: CAR_CAIP already set\n", __FUNCTION__);
+ goto out;
+ }
+
+ /* set up primary or secondary codec space */
+ reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
+ reg_addr += (reg >> 1);
+ gsr_bits = 0;
+ *reg_addr = val;
+ wait_event_timeout(gsr_wq, gsr_bits & GSR_CDONE, 1);
+ if (!gsr_bits & GSR_SDONE)
+ printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
+ __FUNCTION__, reg, gsr_bits);
+
+out: up(&car_mutex);
+}
+
+static void pxa2xx_ac97_reset(ac97_t *ac97)
+{
+ /* First, try cold reset */
+ GCR &= GCR_COLD_RST; /* clear everything but nCRST */
+ GCR &= ~GCR_COLD_RST; /* then assert nCRST */
+
+ gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+ /* PXA27x Developers Manual section 13.5.2.2.1 */
+ pxa_set_cken(1 << 31, 1);
+ udelay(5);
+ pxa_set_cken(1 << 31, 0);
+ GCR = GCR_COLD_RST;
+ udelay(50);
+#else
+ GCR = GCR_COLD_RST;
+ GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+ wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+ if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+ printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+ __FUNCTION__, gsr_bits);
+
+ /* let's try warm reset */
+ gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+ /* warm reset broken on Bulverde,
+ so manually keep AC97 reset high */
+ pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH);
+ udelay(10);
+ GCR |= GCR_WARM_RST;
+ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ udelay(500);
+#else
+ GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;
+ wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+ if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+ printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+ __FUNCTION__, gsr_bits);
+ }
+
+ GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+ GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ long status;
+
+ status = GSR;
+ if (status) {
+ GSR = status;
+ gsr_bits |= status;
+ wake_up(&gsr_wq);
+
+#ifdef CONFIG_PXA27x
+ /* Although we don't use those we still need to clear them
+ since they tend to spuriously trigger when MMC is used
+ (hardware bug? go figure)... */
+ MISR = MISR_EOC;
+ PISR = PISR_EOC;
+ MCSR = MCSR_EOC;
+#endif
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static ac97_bus_ops_t pxa2xx_ac97_ops = {
+ .read = pxa2xx_ac97_read,
+ .write = pxa2xx_ac97_write,
+ .reset = pxa2xx_ac97_reset,
+};
+
+static pxa2xx_pcm_dma_params_t pxa2xx_ac97_pcm_out = {
+ .name = "AC97 PCM out",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRTXPCDR,
+ .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static pxa2xx_pcm_dma_params_t pxa2xx_ac97_pcm_in = {
+ .name = "AC97 PCM in",
+ .dev_addr = __PREG(PCDR),
+ .drcmr = &DRCMRRXPCDR,
+ .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
+ DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static snd_pcm_t *pxa2xx_ac97_pcm;
+static ac97_t *pxa2xx_ac97_ac97;
+
+static int pxa2xx_ac97_pcm_startup(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ pxa2xx_audio_ops_t *platform_ops;
+ int r;
+
+ runtime->hw.channels_min = 2;
+ runtime->hw.channels_max = 2;
+
+ r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
+ runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
+ snd_pcm_limit_hw_rates(runtime);
+
+ platform_ops = substream->pcm->card->dev->platform_data;
+ if (platform_ops && platform_ops->startup)
+ return platform_ops->startup(substream, platform_ops->priv);
+ else
+ return 0;
+}
+
+static void pxa2xx_ac97_pcm_shutdown(snd_pcm_substream_t *substream)
+{
+ pxa2xx_audio_ops_t *platform_ops;
+
+ platform_ops = substream->pcm->card->dev->platform_data;
+ if (platform_ops && platform_ops->shutdown)
+ platform_ops->shutdown(substream, platform_ops->priv);
+}
+
+static int pxa2xx_ac97_pcm_prepare(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+ return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
+}
+
+static pxa2xx_pcm_client_t pxa2xx_ac97_pcm_client = {
+ .playback_params = &pxa2xx_ac97_pcm_out,
+ .capture_params = &pxa2xx_ac97_pcm_in,
+ .startup = pxa2xx_ac97_pcm_startup,
+ .shutdown = pxa2xx_ac97_pcm_shutdown,
+ .prepare = pxa2xx_ac97_pcm_prepare,
+};
+
+#ifdef CONFIG_PM
+
+static int pxa2xx_ac97_do_suspend(snd_card_t *card, unsigned int state)
+{
+ if (card->power_state != SNDRV_CTL_POWER_D3cold) {
+ pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+ snd_pcm_suspend_all(pxa2xx_ac97_pcm);
+ snd_ac97_suspend(pxa2xx_ac97_ac97);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
+ if (platform_ops && platform_ops->suspend)
+ platform_ops->suspend(platform_ops->priv);
+ GCR |= GCR_ACLINK_OFF;
+ pxa_set_cken(CKEN2_AC97, 0);
+ }
+
+ return 0;
+}
+
+static int pxa2xx_ac97_do_resume(snd_card_t *card)
+{
+ if (card->power_state != SNDRV_CTL_POWER_D0) {
+ pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+ pxa_set_cken(CKEN2_AC97, 1);
+ if (platform_ops && platform_ops->resume)
+ platform_ops->resume(platform_ops->priv);
+ snd_ac97_resume(pxa2xx_ac97_ac97);
+ snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+ }
+
+ return 0;
+}
+
+static int pxa2xx_ac97_suspend(struct device *_dev, pm_message_t state, u32 level)
+{
+ snd_card_t *card = dev_get_drvdata(_dev);
+ int ret = 0;
+
+ if (card && level == SUSPEND_DISABLE)
+ ret = pxa2xx_ac97_do_suspend(card, PMSG_SUSPEND);
+
+ return ret;
+}
+
+static int pxa2xx_ac97_resume(struct device *_dev, u32 level)
+{
+ snd_card_t *card = dev_get_drvdata(_dev);
+ int ret = 0;
+
+ if (card && level == RESUME_ENABLE)
+ ret = pxa2xx_ac97_do_resume(card);
+
+ return ret;
+}
+
+#else
+#define pxa2xx_ac97_suspend NULL
+#define pxa2xx_ac97_resume NULL
+#endif
+
+static int pxa2xx_ac97_probe(struct device *dev)
+{
+ snd_card_t *card;
+ ac97_bus_t *ac97_bus;
+ ac97_template_t ac97_template;
+ int ret;
+
+ ret = -ENOMEM;
+ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0);
+ if (!card)
+ goto err;
+
+ card->dev = dev;
+ strncpy(card->driver, dev->driver->name, sizeof(card->driver));
+
+ ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
+ if (ret)
+ goto err;
+
+ ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
+ if (ret < 0)
+ goto err;
+
+ pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+ pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+ pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+ pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+ /* Use GPIO 113 as AC97 Reset on Bulverde */
+ pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+ pxa_set_cken(CKEN2_AC97, 1);
+
+ ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
+ if (ret)
+ goto err;
+ memset(&ac97_template, 0, sizeof(ac97_template));
+ ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
+ if (ret)
+ goto err;
+
+ snprintf(card->shortname, sizeof(card->shortname),
+ "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s (%s)", dev->driver->name, card->mixername);
+
+ snd_card_set_pm_callback(card, pxa2xx_ac97_do_suspend,
+ pxa2xx_ac97_do_resume, NULL);
+ ret = snd_card_register(card);
+ if (ret == 0) {
+ dev_set_drvdata(dev, card);
+ return 0;
+ }
+
+ err:
+ if (card)
+ snd_card_free(card);
+ if (CKEN & CKEN2_AC97) {
+ GCR |= GCR_ACLINK_OFF;
+ free_irq(IRQ_AC97, NULL);
+ pxa_set_cken(CKEN2_AC97, 0);
+ }
+ return ret;
+}
+
+static int pxa2xx_ac97_remove(struct device *dev)
+{
+ snd_card_t *card = dev_get_drvdata(dev);
+
+ if (card) {
+ snd_card_free(card);
+ dev_set_drvdata(dev, NULL);
+ GCR |= GCR_ACLINK_OFF;
+ free_irq(IRQ_AC97, NULL);
+ pxa_set_cken(CKEN2_AC97, 0);
+ }
+
+ return 0;
+}
+
+static struct device_driver pxa2xx_ac97_driver = {
+ .name = "pxa2xx-ac97",
+ .bus = &platform_bus_type,
+ .probe = pxa2xx_ac97_probe,
+ .remove = pxa2xx_ac97_remove,
+ .suspend = pxa2xx_ac97_suspend,
+ .resume = pxa2xx_ac97_resume,
+};
+
+static int __init pxa2xx_ac97_init(void)
+{
+ return driver_register(&pxa2xx_ac97_driver);
+}
+
+static void __exit pxa2xx_ac97_exit(void)
+{
+ driver_unregister(&pxa2xx_ac97_driver);
+}
+
+module_init(pxa2xx_ac97_init);
+module_exit(pxa2xx_ac97_exit);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
new file mode 100644
index 000000000000..b1eb53b02eae
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm.c
@@ -0,0 +1,367 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: (C) 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "pxa2xx-pcm.h"
+
+
+static const snd_pcm_hardware_t pxa2xx_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192 - 32,
+ .periods_min = 1,
+ .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc),
+ .buffer_bytes_max = 128 * 1024,
+ .fifo_size = 32,
+};
+
+struct pxa2xx_runtime_data {
+ int dma_ch;
+ pxa2xx_pcm_dma_params_t *params;
+ pxa_dma_desc *dma_desc_array;
+ dma_addr_t dma_desc_array_phys;
+};
+
+static int pxa2xx_pcm_hw_params(snd_pcm_substream_t *substream,
+ snd_pcm_hw_params_t *params)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *rtd = runtime->private_data;
+ size_t totsize = params_buffer_bytes(params);
+ size_t period = params_period_bytes(params);
+ pxa_dma_desc *dma_desc;
+ dma_addr_t dma_buff_phys, next_desc_phys;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totsize;
+
+ dma_desc = rtd->dma_desc_array;
+ next_desc_phys = rtd->dma_desc_array_phys;
+ dma_buff_phys = runtime->dma_addr;
+ do {
+ next_desc_phys += sizeof(pxa_dma_desc);
+ dma_desc->ddadr = next_desc_phys;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_desc->dsadr = dma_buff_phys;
+ dma_desc->dtadr = rtd->params->dev_addr;
+ } else {
+ dma_desc->dsadr = rtd->params->dev_addr;
+ dma_desc->dtadr = dma_buff_phys;
+ }
+ if (period > totsize)
+ period = totsize;
+ dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+ dma_desc++;
+ dma_buff_phys += period;
+ } while (totsize -= period);
+ dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+
+ return 0;
+}
+
+static int pxa2xx_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+ struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+ *rtd->params->drcmr = 0;
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int pxa2xx_pcm_prepare(snd_pcm_substream_t *substream)
+{
+ pxa2xx_pcm_client_t *client = substream->private_data;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *rtd = runtime->private_data;
+
+ DCSR(rtd->dma_ch) &= ~DCSR_RUN;
+ DCSR(rtd->dma_ch) = 0;
+ DCMD(rtd->dma_ch) = 0;
+ *rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD;
+
+ return client->prepare(substream);
+}
+
+static int pxa2xx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+ struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys;
+ DCSR(rtd->dma_ch) = DCSR_RUN;
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ DCSR(rtd->dma_ch) &= ~DCSR_RUN;
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ DCSR(rtd->dma_ch) |= DCSR_RUN;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs)
+{
+ snd_pcm_substream_t *substream = dev_id;
+ struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+ int dcsr;
+
+ dcsr = DCSR(dma_ch);
+ DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+ if (dcsr & DCSR_ENDINTR) {
+ snd_pcm_period_elapsed(substream);
+ } else {
+ printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+ rtd->params->name, dma_ch, dcsr );
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ }
+}
+
+static snd_pcm_uframes_t pxa2xx_pcm_pointer(snd_pcm_substream_t *substream)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *rtd = runtime->private_data;
+ dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch);
+ snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+ if (x == runtime->buffer_size)
+ x = 0;
+ return x;
+}
+
+static int
+pxa2xx_pcm_hw_rule_mult32(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+{
+ snd_interval_t *i = hw_param_interval(params, rule->var);
+ int changed = 0;
+
+ if (i->min & 31) {
+ i->min = (i->min & ~31) + 32;
+ i->openmin = 0;
+ changed = 1;
+ }
+
+ if (i->max & 31) {
+ i->max &= ~31;
+ i->openmax = 0;
+ changed = 1;
+ }
+
+ return changed;
+}
+
+static int pxa2xx_pcm_open(snd_pcm_substream_t *substream)
+{
+ pxa2xx_pcm_client_t *client = substream->private_data;
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ struct pxa2xx_runtime_data *rtd;
+ int ret;
+
+ runtime->hw = pxa2xx_pcm_hardware;
+
+ /*
+ * For mysterious reasons (and despite what the manual says)
+ * playback samples are lost if the DMA count is not a multiple
+ * of the DMA burst size. Let's add a rule to enforce that.
+ */
+ ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ pxa2xx_pcm_hw_rule_mult32, NULL,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
+ if (ret)
+ goto out;
+ ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ pxa2xx_pcm_hw_rule_mult32, NULL,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
+ if (ret)
+ goto out;
+
+ ret = -ENOMEM;
+ rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+ goto out;
+ rtd->dma_desc_array =
+ dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+ &rtd->dma_desc_array_phys, GFP_KERNEL);
+ if (!rtd->dma_desc_array)
+ goto err1;
+
+ rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ client->playback_params : client->capture_params;
+ ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
+ pxa2xx_pcm_dma_irq, substream);
+ if (ret < 0)
+ goto err2;
+ rtd->dma_ch = ret;
+
+ runtime->private_data = rtd;
+ ret = client->startup(substream);
+ if (!ret)
+ goto out;
+
+ pxa_free_dma(rtd->dma_ch);
+ err2:
+ dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+ rtd->dma_desc_array, rtd->dma_desc_array_phys);
+ err1:
+ kfree(rtd);
+ out:
+ return ret;
+}
+
+static int pxa2xx_pcm_close(snd_pcm_substream_t *substream)
+{
+ pxa2xx_pcm_client_t *client = substream->private_data;
+ struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+ pxa_free_dma(rtd->dma_ch);
+ client->shutdown(substream);
+ dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+ rtd->dma_desc_array, rtd->dma_desc_array_phys);
+ kfree(rtd);
+ return 0;
+}
+
+static int
+pxa2xx_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static snd_pcm_ops_t pxa2xx_pcm_ops = {
+ .open = pxa2xx_pcm_open,
+ .close = pxa2xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pxa2xx_pcm_hw_params,
+ .hw_free = pxa2xx_pcm_hw_free,
+ .prepare = pxa2xx_pcm_prepare,
+ .trigger = pxa2xx_pcm_trigger,
+ .pointer = pxa2xx_pcm_pointer,
+ .mmap = pxa2xx_pcm_mmap,
+};
+
+static int pxa2xx_pcm_preallocate_dma_buffer(snd_pcm_t *pcm, int stream)
+{
+ snd_pcm_substream_t *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ return 0;
+}
+
+static void pxa2xx_pcm_free_dma_buffers(snd_pcm_t *pcm)
+{
+ snd_pcm_substream_t *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 pxa2xx_pcm_dmamask = 0xffffffff;
+
+int pxa2xx_pcm_new(snd_card_t *card, pxa2xx_pcm_client_t *client, snd_pcm_t **rpcm)
+{
+ snd_pcm_t *pcm;
+ int play = client->playback_params ? 1 : 0;
+ int capt = client->capture_params ? 1 : 0;
+ int ret;
+
+ ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
+ if (ret)
+ goto out;
+
+ pcm->private_data = client;
+ pcm->private_free = pxa2xx_pcm_free_dma_buffers;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &pxa2xx_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (play) {
+ int stream = SNDRV_PCM_STREAM_PLAYBACK;
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+ if (ret)
+ goto out;
+ }
+ if (capt) {
+ int stream = SNDRV_PCM_STREAM_CAPTURE;
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+ if (ret)
+ goto out;
+ }
+
+ if (rpcm)
+ *rpcm = pcm;
+ ret = 0;
+
+ out:
+ return ret;
+}
+
+EXPORT_SYMBOL(pxa2xx_pcm_new);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
new file mode 100644
index 000000000000..43517597cab9
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 30, 2004
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+typedef struct {
+ char *name; /* stream identifier */
+ u32 dcmd; /* DMA descriptor dcmd field */
+ volatile u32 *drcmr; /* the DMA request channel to use */
+ u32 dev_addr; /* device physical address for DMA */
+} pxa2xx_pcm_dma_params_t;
+
+typedef struct {
+ pxa2xx_pcm_dma_params_t *playback_params;
+ pxa2xx_pcm_dma_params_t *capture_params;
+ int (*startup)(snd_pcm_substream_t *);
+ void (*shutdown)(snd_pcm_substream_t *);
+ int (*prepare)(snd_pcm_substream_t *);
+} pxa2xx_pcm_client_t;
+
+extern int pxa2xx_pcm_new(snd_card_t *, pxa2xx_pcm_client_t *, snd_pcm_t **);
+
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 764ac184b223..969d75528bde 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -5,7 +5,7 @@
snd-objs := sound.o init.o memory.o info.o control.o misc.o \
device.o wrappers.o
-ifeq ($(CONFIG_ISA),y)
+ifeq ($(CONFIG_ISA_DMA_API),y)
snd-objs += isadma.o
endif
ifeq ($(CONFIG_SND_OSSEMUL),y)
diff --git a/sound/core/device.c b/sound/core/device.c
index 18c71f913d2a..ca00ad7740c9 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -28,7 +28,7 @@
/**
* snd_device_new - create an ALSA device component
* @card: the card instance
- * @type: the device type, SNDRV_DEV_TYPE_XXX
+ * @type: the device type, SNDRV_DEV_XXX
* @device_data: the data pointer of this device
* @ops: the operator table
*
@@ -46,7 +46,9 @@ int snd_device_new(snd_card_t *card, snd_device_type_t type,
{
snd_device_t *dev;
- snd_assert(card != NULL && device_data != NULL && ops != NULL, return -ENXIO);
+ snd_assert(card != NULL, return -ENXIO);
+ snd_assert(device_data != NULL, return -ENXIO);
+ snd_assert(ops != NULL, return -ENXIO);
dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
@@ -102,7 +104,7 @@ int snd_device_free(snd_card_t *card, void *device_data)
}
/**
- * snd_device_free - disconnect the device
+ * snd_device_disconnect - disconnect the device
* @card: the card instance
* @device_data: the data pointer to disconnect
*
@@ -118,7 +120,7 @@ int snd_device_disconnect(snd_card_t *card, void *device_data)
{
struct list_head *list;
snd_device_t *dev;
-
+
snd_assert(card != NULL, return -ENXIO);
snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
@@ -154,8 +156,9 @@ int snd_device_register(snd_card_t *card, void *device_data)
struct list_head *list;
snd_device_t *dev;
int err;
-
- snd_assert(card != NULL && device_data != NULL, return -ENXIO);
+
+ snd_assert(card != NULL, return -ENXIO);
+ snd_assert(device_data != NULL, return -ENXIO);
list_for_each(list, &card->devices) {
dev = snd_device(list);
if (dev->device_data != device_data)
diff --git a/sound/core/info.c b/sound/core/info.c
index 5e122bbe7c92..7f8bdf7b0058 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -702,7 +702,7 @@ int snd_info_get_line(snd_info_buffer_t * buffer, char *line, int len)
}
/**
- * snd_info_get_line - parse a string token
+ * snd_info_get_str - parse a string token
* @dest: the buffer to store the string token
* @src: the original string
* @len: the max. length of token - 1
@@ -939,7 +939,8 @@ int snd_info_unregister(snd_info_entry_t * entry)
{
struct proc_dir_entry *root;
- snd_assert(entry != NULL && entry->p != NULL, return -ENXIO);
+ snd_assert(entry != NULL, return -ENXIO);
+ snd_assert(entry->p != NULL, return -ENXIO);
root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
snd_assert(root, return -ENXIO);
down(&info_mutex);
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index dbc23e35fa06..39a54a415528 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -105,7 +105,8 @@ struct snd_mem_list {
*/
static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, int flags)
+ dma_addr_t *dma_handle,
+ unsigned int __nocast flags)
{
void *ret;
u64 dma_mask, coherent_dma_mask;
@@ -511,7 +512,7 @@ static void free_all_reserved_pages(void)
* proc file interface
*/
#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
-struct proc_dir_entry *snd_mem_proc;
+static struct proc_dir_entry *snd_mem_proc;
static int snd_mem_proc_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
@@ -654,8 +655,7 @@ static int __init snd_mem_init(void)
static void __exit snd_mem_exit(void)
{
- if (snd_mem_proc)
- remove_proc_entry(SND_MEM_PROC_FILE, NULL);
+ remove_proc_entry(SND_MEM_PROC_FILE, NULL);
free_all_reserved_pages();
if (snd_allocated_pages > 0)
printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
diff --git a/sound/core/memory.c b/sound/core/memory.c
index c1fb28e84330..1622893d00a2 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -56,7 +56,7 @@ static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
#define VMALLOC_MAGIC 0x87654320
static snd_info_entry_t *snd_memory_info_entry;
-void snd_memory_init(void)
+void __init snd_memory_init(void)
{
snd_alloc_kmalloc = 0;
snd_alloc_vmalloc = 0;
@@ -89,7 +89,7 @@ void snd_memory_done(void)
}
}
-static void *__snd_kmalloc(size_t size, int flags, void *caller)
+static void *__snd_kmalloc(size_t size, unsigned int __nocast flags, void *caller)
{
unsigned long cpu_flags;
struct snd_alloc_track *t;
@@ -111,12 +111,12 @@ static void *__snd_kmalloc(size_t size, int flags, void *caller)
}
#define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0));
-void *snd_hidden_kmalloc(size_t size, int flags)
+void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags)
{
return _snd_kmalloc(size, flags);
}
-void *snd_hidden_kcalloc(size_t n, size_t size, int flags)
+void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags)
{
void *ret = NULL;
if (n != 0 && size > INT_MAX / n)
@@ -184,7 +184,7 @@ void snd_hidden_vfree(void *obj)
snd_wrapper_vfree(obj);
}
-char *snd_hidden_kstrdup(const char *s, int flags)
+char *snd_hidden_kstrdup(const char *s, unsigned int __nocast flags)
{
int len;
char *buf;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index de7444c586f9..a13bd7bb4c9f 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1705,13 +1705,12 @@ static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
if (snd_pcm_running(substream))
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
snd_pcm_stream_unlock_irq(substream);
- if (substream->open_flag) {
+ if (substream->ffile != NULL) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
- substream->open_flag = 0;
+ substream->ffile = NULL;
}
- substream->ffile = NULL;
snd_pcm_oss_release_substream(substream);
snd_pcm_release_substream(substream);
}
@@ -1778,14 +1777,13 @@ static int snd_pcm_oss_open_file(struct file *file,
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- psubstream->open_flag = 1;
+ psubstream->ffile = file;
err = snd_pcm_hw_constraints_complete(psubstream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraint_complete failed\n");
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- psubstream->ffile = file;
snd_pcm_oss_init_substream(psubstream, psetup, minor);
}
if (csubstream != NULL) {
@@ -1800,14 +1798,13 @@ static int snd_pcm_oss_open_file(struct file *file,
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- csubstream->open_flag = 1;
+ csubstream->ffile = file;
err = snd_pcm_hw_constraints_complete(csubstream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraint_complete failed\n");
snd_pcm_oss_release_file(pcm_oss_file);
return err;
}
- csubstream->ffile = file;
snd_pcm_oss_init_substream(csubstream, csetup, minor);
}
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
index 3920bf0eebbf..4b6307df846d 100644
--- a/sound/core/pcm_compat.c
+++ b/sound/core/pcm_compat.c
@@ -103,10 +103,24 @@ struct sndrv_pcm_sw_params32 {
unsigned char reserved[64];
};
+/* recalcuate the boundary within 32bit */
+static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime)
+{
+ snd_pcm_uframes_t boundary;
+
+ if (! runtime->buffer_size)
+ return 0;
+ boundary = runtime->buffer_size;
+ while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
+ boundary *= 2;
+ return boundary;
+}
+
static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
struct sndrv_pcm_sw_params32 __user *src)
{
snd_pcm_sw_params_t params;
+ snd_pcm_uframes_t boundary;
int err;
memset(&params, 0, sizeof(params));
@@ -120,10 +134,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
get_user(params.silence_threshold, &src->silence_threshold) ||
get_user(params.silence_size, &src->silence_size))
return -EFAULT;
+ /*
+ * Check silent_size parameter. Since we have 64bit boundary,
+ * silence_size must be compared with the 32bit boundary.
+ */
+ boundary = recalculate_boundary(substream->runtime);
+ if (boundary && params.silence_size >= boundary)
+ params.silence_size = substream->runtime->boundary;
err = snd_pcm_sw_params(substream, &params);
if (err < 0)
return err;
- if (put_user(params.boundary, &src->boundary))
+ if (boundary && put_user(boundary, &src->boundary))
return -EFAULT;
return err;
}
@@ -199,16 +220,6 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
return err;
}
-/* recalcuate the boundary within 32bit */
-static void recalculate_boundary(snd_pcm_runtime_t *runtime)
-{
- if (! runtime->buffer_size)
- return;
- runtime->boundary = runtime->buffer_size;
- while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
- runtime->boundary *= 2;
-}
-
/* both for HW_PARAMS and HW_REFINE */
static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
int refine,
@@ -241,8 +252,11 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
goto error;
}
- if (! refine)
- recalculate_boundary(runtime);
+ if (! refine) {
+ unsigned int new_boundary = recalculate_boundary(runtime);
+ if (new_boundary)
+ runtime->boundary = new_boundary;
+ }
error:
kfree(data);
return err;
@@ -380,6 +394,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
u32 sflags;
struct sndrv_pcm_mmap_control scontrol;
struct sndrv_pcm_mmap_status sstatus;
+ snd_pcm_uframes_t boundary;
int err;
snd_assert(runtime, return -EINVAL);
@@ -395,17 +410,21 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
}
status = runtime->status;
control = runtime->control;
+ boundary = recalculate_boundary(runtime);
+ if (! boundary)
+ boundary = 0x7fffffff;
snd_pcm_stream_lock_irq(substream);
+ /* FIXME: we should consider the boundary for the sync from app */
if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
control->appl_ptr = scontrol.appl_ptr;
else
- scontrol.appl_ptr = control->appl_ptr;
+ scontrol.appl_ptr = control->appl_ptr % boundary;
if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
control->avail_min = scontrol.avail_min;
else
scontrol.avail_min = control->avail_min;
sstatus.state = status->state;
- sstatus.hw_ptr = status->hw_ptr;
+ sstatus.hw_ptr = status->hw_ptr % boundary;
sstatus.tstamp = status->tstamp;
sstatus.suspended_state = status->suspended_state;
snd_pcm_stream_unlock_irq(substream);
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index c5bfd0918cff..0082914a7e33 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1584,8 +1584,8 @@ int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
return snd_pcm_hw_param_value(params, var, NULL);
}
-int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
- snd_pcm_hw_param_t var, const snd_mask_t *val)
+static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
+ snd_pcm_hw_param_t var, const snd_mask_t *val)
{
int changed;
assert(hw_is_mask(var));
@@ -2063,7 +2063,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
if (((avail < runtime->control->avail_min && size > avail) ||
(size >= runtime->xfer_align && avail < runtime->xfer_align))) {
wait_queue_t wait;
- enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+ enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
long tout;
if (nonblock) {
@@ -2097,6 +2097,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
case SNDRV_PCM_STATE_SUSPENDED:
state = SUSPENDED;
goto _end_loop;
+ case SNDRV_PCM_STATE_SETUP:
+ state = DROPPED;
+ goto _end_loop;
default:
break;
}
@@ -2123,6 +2126,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
snd_printd("playback write error (DMA or IRQ trouble?)\n");
err = -EIO;
goto _end_unlock;
+ case DROPPED:
+ err = -EBADFD;
+ goto _end_unlock;
default:
break;
}
@@ -2359,7 +2365,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
} else if ((avail < runtime->control->avail_min && size > avail) ||
(size >= runtime->xfer_align && avail < runtime->xfer_align)) {
wait_queue_t wait;
- enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+ enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED, DROPPED } state;
long tout;
if (nonblock) {
@@ -2394,6 +2400,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
goto _end_loop;
case SNDRV_PCM_STATE_DRAINING:
goto __draining;
+ case SNDRV_PCM_STATE_SETUP:
+ state = DROPPED;
+ goto _end_loop;
default:
break;
}
@@ -2420,6 +2429,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
snd_printd("capture read error (DMA or IRQ trouble?)\n");
err = -EIO;
goto _end_unlock;
+ case DROPPED:
+ err = -EBADFD;
+ goto _end_unlock;
default:
break;
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 10c2c9832649..03c17159dd8e 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1025,7 +1025,7 @@ static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND, &runtime->trigger_tstamp);
runtime->status->suspended_state = runtime->status->state;
runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
snd_pcm_tick_set(substream, 0);
@@ -1115,7 +1115,7 @@ static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
snd_pcm_runtime_t *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
if (substream->timer)
- snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
+ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp);
runtime->status->state = runtime->status->suspended_state;
if (runtime->sleep_min)
snd_pcm_tick_prepare(substream);
@@ -1967,13 +1967,12 @@ static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
runtime = substream->runtime;
str = substream->pstr;
snd_pcm_unlink(substream);
- if (substream->open_flag) {
+ if (substream->ffile != NULL) {
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
substream->ops->close(substream);
- substream->open_flag = 0;
+ substream->ffile = NULL;
}
- substream->ffile = NULL;
snd_pcm_remove_file(str, pcm_file);
snd_pcm_release_substream(substream);
kfree(pcm_file);
@@ -2022,18 +2021,15 @@ static int snd_pcm_open_file(struct file *file,
snd_pcm_release_file(pcm_file);
return err;
}
- substream->open_flag = 1;
+ substream->ffile = file;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_complete failed\n");
- substream->ops->close(substream);
snd_pcm_release_file(pcm_file);
return err;
}
- substream->ffile = file;
-
file->private_data = pcm_file;
*rpcm_file = pcm_file;
return 0;
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 64cb50d7b589..402e2b4a34c6 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-instr.o
+obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o
obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
index 0779c41ca037..32e91c6b25fe 100644
--- a/sound/core/seq/instr/ainstr_gf1.c
+++ b/sound/core/seq/instr/ainstr_gf1.c
@@ -50,7 +50,8 @@ static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t *ops,
{
gf1_wave_t *wp, *prev;
gf1_xwave_t xp;
- int err, gfp_mask;
+ int err;
+ unsigned int gfp_mask;
unsigned int real_size;
gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
index 39ff72b2aab3..2622b8679ca7 100644
--- a/sound/core/seq/instr/ainstr_iw.c
+++ b/sound/core/seq/instr/ainstr_iw.c
@@ -58,7 +58,7 @@ static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,
iwffff_xenv_t *ex,
char __user **data,
long *len,
- int gfp_mask)
+ unsigned int __nocast gfp_mask)
{
__u32 stype;
iwffff_env_record_t *rp, *rp_last;
@@ -128,7 +128,8 @@ static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops,
{
iwffff_wave_t *wp, *prev;
iwffff_xwave_t xp;
- int err, gfp_mask;
+ int err;
+ unsigned int gfp_mask;
unsigned int real_size;
gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
@@ -234,7 +235,8 @@ static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr,
iwffff_xinstrument_t ix;
iwffff_layer_t *lp, *prev_lp;
iwffff_xlayer_t lx;
- int err, gfp_mask;
+ int err;
+ unsigned int gfp_mask;
if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
return -EINVAL;
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index da23c4db8dd5..973786758c55 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -158,21 +158,21 @@ void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf);
#define is_nonblock_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_NONBLOCK)
/* dispatch event */
-inline static int
+static inline int
snd_seq_oss_dispatch(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int atomic, int hop)
{
return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
}
/* ioctl */
-inline static int
+static inline int
snd_seq_oss_control(seq_oss_devinfo_t *dp, unsigned int type, void *arg)
{
return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
}
/* fill the addresses in header */
-inline static void
+static inline void
snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev,
int dest_client, int dest_port)
{
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 00d841e82fbc..03acb2d519ba 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -36,12 +36,12 @@
#define semaphore_of(fp) ((fp)->f_dentry->d_inode->i_sem)
-inline static int snd_seq_pool_available(pool_t *pool)
+static inline int snd_seq_pool_available(pool_t *pool)
{
return pool->total_elements - atomic_read(&pool->counter);
}
-inline static int snd_seq_output_ok(pool_t *pool)
+static inline int snd_seq_output_ok(pool_t *pool)
{
return snd_seq_pool_available(pool) >= pool->room;
}
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 57be9155eb62..4374829ea770 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -134,7 +134,7 @@ static int event_process_midi(snd_seq_event_t * ev, int direct,
seq_midisynth_t *msynth = (seq_midisynth_t *) private_data;
unsigned char msg[10]; /* buffer for constructing midi messages */
snd_rawmidi_substream_t *substream;
- int res;
+ int len;
snd_assert(msynth != NULL, return -EINVAL);
substream = msynth->output_rfile.output;
@@ -146,20 +146,16 @@ static int event_process_midi(snd_seq_event_t * ev, int direct,
snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
return 0;
}
- res = snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
+ snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
snd_midi_event_reset_decode(msynth->parser);
- if (res < 0)
- return res;
} else {
if (msynth->parser == NULL)
return -EIO;
- res = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
- if (res < 0)
- return res;
- if ((res = dump_midi(substream, msg, res)) < 0) {
+ len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
+ if (len < 0)
+ return 0;
+ if (dump_midi(substream, msg, len) < 0)
snd_midi_event_reset_decode(msynth->parser);
- return res;
- }
}
return 0;
}
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index df1e2bb39745..603b63716db6 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -146,7 +146,7 @@ void snd_midi_event_free(snd_midi_event_t *dev)
/*
* initialize record
*/
-inline static void reset_encode(snd_midi_event_t *dev)
+static inline void reset_encode(snd_midi_event_t *dev)
{
dev->read = 0;
dev->qlen = 0;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 7612884f530b..3271e9245490 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -432,7 +432,7 @@ EXPORT_SYMBOL(snd_device_new);
EXPORT_SYMBOL(snd_device_register);
EXPORT_SYMBOL(snd_device_free);
/* isadma.c */
-#ifdef CONFIG_ISA
+#ifdef CONFIG_ISA_DMA_API
EXPORT_SYMBOL(snd_dma_program);
EXPORT_SYMBOL(snd_dma_disable);
EXPORT_SYMBOL(snd_dma_pointer);
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index de39d212bc15..e401c6703297 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -98,6 +98,7 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
int cidx = SNDRV_MINOR_OSS_CARD(minor);
int track2 = -1;
int register1 = -1, register2 = -1;
+ struct device *carddev = NULL;
if (minor < 0)
return minor;
@@ -121,11 +122,13 @@ int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t *
track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
break;
}
- register1 = register_sound_special(reg->f_ops, minor);
+ if (card)
+ carddev = card->dev;
+ register1 = register_sound_special_device(reg->f_ops, minor, carddev);
if (register1 != minor)
goto __end;
if (track2 >= 0) {
- register2 = register_sound_special(reg->f_ops, track2);
+ register2 = register_sound_special_device(reg->f_ops, track2, carddev);
if (register2 != track2)
goto __end;
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index cfaccd415b3b..4104f6e292e9 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -799,13 +799,13 @@ static int snd_timer_free(snd_timer_t *timer)
return 0;
}
-int snd_timer_dev_free(snd_device_t *device)
+static int snd_timer_dev_free(snd_device_t *device)
{
snd_timer_t *timer = device->device_data;
return snd_timer_free(timer);
}
-int snd_timer_dev_register(snd_device_t *dev)
+static int snd_timer_dev_register(snd_device_t *dev)
{
snd_timer_t *timer = dev->device_data;
snd_timer_t *timer1;
@@ -880,9 +880,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
struct list_head *p, *n;
snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);
- snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
+ snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MRESUME, return);
spin_lock_irqsave(&timer->lock, flags);
- if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
+ if (event == SNDRV_TIMER_EVENT_MSTART ||
+ event == SNDRV_TIMER_EVENT_MCONTINUE ||
+ event == SNDRV_TIMER_EVENT_MRESUME) {
if (timer->hw.c_resolution)
resolution = timer->hw.c_resolution(timer);
else
@@ -1555,10 +1557,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
(1<<SNDRV_TIMER_EVENT_STOP)|
(1<<SNDRV_TIMER_EVENT_CONTINUE)|
(1<<SNDRV_TIMER_EVENT_PAUSE)|
+ (1<<SNDRV_TIMER_EVENT_SUSPEND)|
+ (1<<SNDRV_TIMER_EVENT_RESUME)|
(1<<SNDRV_TIMER_EVENT_MSTART)|
(1<<SNDRV_TIMER_EVENT_MSTOP)|
(1<<SNDRV_TIMER_EVENT_MCONTINUE)|
- (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
+ (1<<SNDRV_TIMER_EVENT_MPAUSE)|
+ (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
+ (1<<SNDRV_TIMER_EVENT_MRESUME))) {
err = -EINVAL;
goto _end;
}
diff --git a/sound/core/wrappers.c b/sound/core/wrappers.c
index 9f393023c327..508e6d67ee19 100644
--- a/sound/core/wrappers.c
+++ b/sound/core/wrappers.c
@@ -27,7 +27,7 @@
#include <linux/fs.h>
#ifdef CONFIG_SND_DEBUG_MEMORY
-void *snd_wrapper_kmalloc(size_t size, int flags)
+void *snd_wrapper_kmalloc(size_t size, unsigned int __nocast flags)
{
return kmalloc(size, flags);
}
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 964b97e70c84..986df35fb829 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -168,7 +168,7 @@ typedef struct _snd_uart16550 {
static snd_card_t *snd_serial_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-inline static void snd_uart16550_add_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_add_timer(snd_uart16550_t *uart)
{
if (! uart->timer_running) {
/* timer 38600bps * 10bit * 16byte */
@@ -178,7 +178,7 @@ inline static void snd_uart16550_add_timer(snd_uart16550_t *uart)
}
}
-inline static void snd_uart16550_del_timer(snd_uart16550_t *uart)
+static inline void snd_uart16550_del_timer(snd_uart16550_t *uart)
{
if (uart->timer_running) {
del_timer(&uart->buffer_timer);
@@ -187,7 +187,7 @@ inline static void snd_uart16550_del_timer(snd_uart16550_t *uart)
}
/* This macro is only used in snd_uart16550_io_loop */
-inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart)
+static inline void snd_uart16550_buffer_output(snd_uart16550_t *uart)
{
unsigned short buff_out = uart->buff_out;
if( uart->buff_in_count > 0 ) {
@@ -579,7 +579,7 @@ static int snd_uart16550_output_close(snd_rawmidi_substream_t * substream)
return 0;
};
-inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
+static inline int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num )
{
if( uart->buff_in_count + Num < TX_BUFF_SIZE )
return 1;
@@ -587,7 +587,7 @@ inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num
return 0;
}
-inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
+static inline int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte)
{
unsigned short buff_in = uart->buff_in;
if( uart->buff_in_count < TX_BUFF_SIZE ) {
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index f00c88886460..19fc68c23378 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -796,14 +796,14 @@ static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontro
static snd_kcontrol_new_t vx_control_iec958_mask = {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.info = vx_iec958_info, /* shared */
.get = vx_iec958_mask_get,
};
static snd_kcontrol_new_t vx_control_iec958 = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.info = vx_iec958_info,
.get = vx_iec958_get,
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index af381b15fe5c..d4becf44e247 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -549,8 +549,8 @@ static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe)
static snd_pcm_hardware_t vx_pcm_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+ /*SNDRV_PCM_INFO_RESUME*/),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,
@@ -949,8 +949,8 @@ static snd_pcm_ops_t vx_pcm_playback_ops = {
static snd_pcm_hardware_t vx_pcm_capture_hw = {
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID /*|*/
+ /*SNDRV_PCM_INFO_RESUME*/),
.formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5000,
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index 18114713c3b3..4fc38bde34f4 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -162,34 +162,24 @@ static int vx_read_uer_status(vx_core_t *chip, int *mode)
static int vx_calc_clock_from_freq(vx_core_t *chip, int freq)
{
-#define XX_FECH48000 0x0000004B
-#define XX_FECH32000 0x00000171
-#define XX_FECH24000 0x0000024B
-#define XX_FECH16000 0x00000371
-#define XX_FECH12000 0x0000044B
-#define XX_FECH8000 0x00000571
-#define XX_FECH44100 0x0000007F
-#define XX_FECH29400 0x0000016F
-#define XX_FECH22050 0x0000027F
-#define XX_FECH14000 0x000003EF
-#define XX_FECH11025 0x0000047F
-#define XX_FECH7350 0x000005BF
-
- switch (freq) {
- case 48000: return XX_FECH48000;
- case 44100: return XX_FECH44100;
- case 32000: return XX_FECH32000;
- case 29400: return XX_FECH29400;
- case 24000: return XX_FECH24000;
- case 22050: return XX_FECH22050;
- case 16000: return XX_FECH16000;
- case 14000: return XX_FECH14000;
- case 12000: return XX_FECH12000;
- case 11025: return XX_FECH11025;
- case 8000: return XX_FECH8000;
- case 7350: return XX_FECH7350;
- default: return freq; /* The value is already correct */
- }
+ int hexfreq;
+
+ snd_assert(freq > 0, return 0);
+
+ hexfreq = (28224000 * 10) / freq;
+ hexfreq = (hexfreq + 5) / 10;
+
+ /* max freq = 55125 Hz */
+ snd_assert(hexfreq > 0x00000200, return 0);
+
+ if (hexfreq <= 0x03ff)
+ return hexfreq - 0x00000201;
+ if (hexfreq <= 0x07ff)
+ return (hexfreq / 2) - 1;
+ if (hexfreq <= 0x0fff)
+ return (hexfreq / 4) + 0x000001ff;
+
+ return 0x5fe; /* min freq = 6893 Hz */
}
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index f5e6018ea3f4..5adde308a00f 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -554,7 +554,6 @@ int snd_ak4114_check_rate_and_errors(ak4114_t *ak4114, unsigned int flags)
if (snd_pcm_running(ak4114->capture_substream)) {
// printk("rate changed (%i <- %i)\n", runtime->rate, res);
snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING);
- wake_up(&runtime->sleep);
res = 1;
}
snd_pcm_stream_unlock_irqrestore(ak4114->capture_substream, _flags);
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 148a856a43ad..be4ea60a3679 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -1,7 +1,7 @@
# ALSA ISA drivers
menu "ISA devices"
- depends on SND!=n && ISA
+ depends on SND!=n && ISA && ISA_DMA_API
config SND_AD1848_LIB
tristate
diff --git a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c
index 563296d02894..0eb442ca23d6 100644
--- a/sound/isa/ad1816a/ad1816a.c
+++ b/sound/isa/ad1816a/ad1816a.c
@@ -53,6 +53,7 @@ static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
+static int clockfreq[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for ad1816a based soundcard.");
@@ -74,6 +75,8 @@ module_param_array(dma1, int, NULL, 0444);
MODULE_PARM_DESC(dma1, "1st DMA # for ad1816a driver.");
module_param_array(dma2, int, NULL, 0444);
MODULE_PARM_DESC(dma2, "2nd DMA # for ad1816a driver.");
+module_param_array(clockfreq, int, NULL, 0444);
+MODULE_PARM_DESC(clockfreq, "Clock frequency for ad1816a driver (default = 0).");
struct snd_card_ad1816a {
struct pnp_dev *dev;
@@ -209,6 +212,8 @@ static int __devinit snd_card_ad1816a_probe(int dev, struct pnp_card_link *pcard
snd_card_free(card);
return error;
}
+ if (clockfreq[dev] >= 5000 && clockfreq[dev] <= 100000)
+ chip->clock_freq = clockfreq[dev];
strcpy(card->driver, "AD1816A");
strcpy(card->shortname, "ADI SoundPort AD1816A");
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 625b2eff14a1..ae860360ecf9 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -234,7 +234,7 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
ad1816a_t *chip = snd_pcm_substream_chip(substream);
unsigned long flags;
snd_pcm_runtime_t *runtime = substream->runtime;
- unsigned int size;
+ unsigned int size, rate;
spin_lock_irqsave(&chip->lock, flags);
@@ -245,7 +245,10 @@ static int snd_ad1816a_playback_prepare(snd_pcm_substream_t *substream)
snd_dma_program(chip->dma1, runtime->dma_addr, size,
DMA_MODE_WRITE | DMA_AUTOINIT);
- snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, runtime->rate);
+ rate = runtime->rate;
+ if (chip->clock_freq)
+ rate = (rate * 33000) / chip->clock_freq;
+ snd_ad1816a_write(chip, AD1816A_PLAYBACK_SAMPLE_RATE, rate);
snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
snd_ad1816a_get_format(chip, runtime->format,
@@ -263,7 +266,7 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
ad1816a_t *chip = snd_pcm_substream_chip(substream);
unsigned long flags;
snd_pcm_runtime_t *runtime = substream->runtime;
- unsigned int size;
+ unsigned int size, rate;
spin_lock_irqsave(&chip->lock, flags);
@@ -274,7 +277,10 @@ static int snd_ad1816a_capture_prepare(snd_pcm_substream_t *substream)
snd_dma_program(chip->dma2, runtime->dma_addr, size,
DMA_MODE_READ | DMA_AUTOINIT);
- snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, runtime->rate);
+ rate = runtime->rate;
+ if (chip->clock_freq)
+ rate = (rate * 33000) / chip->clock_freq;
+ snd_ad1816a_write(chip, AD1816A_CAPTURE_SAMPLE_RATE, rate);
snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
AD1816A_FMT_ALL | AD1816A_FMT_STEREO,
snd_ad1816a_get_format(chip, runtime->format,
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 8fb3db103e48..bc642dc94547 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -1196,6 +1196,7 @@ int snd_ad1848_add_ctl(ad1848_t *chip, const char *name, int index, int type, un
.put = snd_ad1848_put_double,
},
[AD1848_MIX_CAPTURE] = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_ad1848_info_mux,
.get = snd_ad1848_get_mux,
.put = snd_ad1848_put_mux,
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 46776cc0c157..1fce8b9f37cf 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -194,8 +194,8 @@ AD1848_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4
AD1848_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1),
AD1848_SINGLE("PC Speaker Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0),
AD1848_SINGLE("FM Playback Switch", 0, CMI8330_RECMUX, 3, 1, 1),
-AD1848_SINGLE("IEC958 Input Capture Switch", 0, CMI8330_RMUX3D, 7, 1, 1),
-AD1848_SINGLE("IEC958 Input Playback Switch", 0, CMI8330_MUTEMUX, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",CAPTURE,SWITCH), 0, CMI8330_RMUX3D, 7, 1, 1),
+AD1848_SINGLE(SNDRV_CTL_NAME_IEC958("Input ",PLAYBACK,SWITCH), 0, CMI8330_MUTEMUX, 7, 1, 1),
};
#ifdef ENABLE_SB_MIXER
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
index 3e7a2a33a5ca..3199941edd9b 100644
--- a/sound/isa/cs423x/cs4231_lib.c
+++ b/sound/isa/cs423x/cs4231_lib.c
@@ -1346,6 +1346,8 @@ static void snd_cs4231_suspend(cs4231_t *chip)
int reg;
unsigned long flags;
+ if (chip->pcm)
+ snd_pcm_suspend_all(chip->pcm);
spin_lock_irqsave(&chip->reg_lock, flags);
for (reg = 0; reg < 32; reg++)
chip->image[reg] = snd_cs4231_in(chip, reg);
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c
index 337b0e2a8a36..23e1b5f19e1a 100644
--- a/sound/isa/gus/gus_io.c
+++ b/sound/isa/gus/gus_io.c
@@ -269,8 +269,9 @@ void snd_gf1_i_write_addr(snd_gus_card_t * gus, unsigned char reg,
#endif /* 0 */
-unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
- unsigned char reg, short w_16bit)
+#ifdef CONFIG_SND_DEBUG
+static unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
+ unsigned char reg, short w_16bit)
{
unsigned int res;
unsigned long flags;
@@ -280,6 +281,7 @@ unsigned int snd_gf1_i_read_addr(snd_gus_card_t * gus,
spin_unlock_irqrestore(&gus->reg_lock, flags);
return res;
}
+#endif
/*
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 94bbd344be5e..a636d9ce3502 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -417,11 +417,13 @@ static int snd_gus_check_version(snd_gus_card_t * gus)
return 0;
}
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
static void snd_gus_seq_dev_free(snd_seq_device_t *seq_dev)
{
snd_gus_card_t *gus = seq_dev->private_data;
gus->seq_dev = NULL;
}
+#endif
int snd_gus_initialize(snd_gus_card_t *gus)
{
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 95c7b3e53407..75bd6eca63e7 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -145,6 +145,14 @@ static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
#ifdef CONFIG_PNP
+static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = {
+ { .id = "YMH0021" },
+ { .id = "NMX2210" }, /* Gateway Solo 2500 */
+ { .id = "" } /* end */
+};
+
+MODULE_DEVICE_TABLE(pnp, snd_opl3sa2_pnpbiosids);
+
static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
/* Yamaha YMF719E-S (Genius Sound Maker 3DX) */
{ .id = "YMH0020", .devs = { { "YMH0021" } } },
@@ -568,20 +576,18 @@ static int snd_opl3sa2_resume(snd_card_t *card)
#ifdef CONFIG_PNP
static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
- struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+ struct pnp_dev *pdev,
+ int isapnp)
{
- struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+ struct pnp_resource_table * cfg;
int err;
+ if (!isapnp && pnp_device_is_isapnp(pdev))
+ return -ENOENT; /* we have another procedure - card */
+
+ cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
- pdev = chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
- if (chip->dev == NULL) {
- kfree(cfg);
- return -EBUSY;
- }
/* PnP initialization */
pnp_init_resource_table(cfg);
if (sb_port[dev] != SNDRV_AUTO_PORT)
@@ -601,7 +607,7 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
if (irq[dev] != SNDRV_AUTO_IRQ)
pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
err = pnp_manual_config_dev(pdev, cfg, 0);
- if (err < 0)
+ if (err < 0 && isapnp)
snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n");
err = pnp_activate_dev(pdev);
if (err < 0) {
@@ -617,13 +623,31 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip,
dma1[dev] = pnp_dma(pdev, 0);
dma2[dev] = pnp_dma(pdev, 1);
irq[dev] = pnp_irq(pdev, 0);
- snd_printdd("PnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
- sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
- snd_printdd("PnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
- port[dev], dma1[dev], dma2[dev], irq[dev]);
+ snd_printdd("%sPnP OPL3-SA: sb port=0x%lx, wss port=0x%lx, fm port=0x%lx, midi port=0x%lx\n",
+ pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", sb_port[dev], wss_port[dev], fm_port[dev], midi_port[dev]);
+ snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n",
+ pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]);
kfree(cfg);
+ chip->dev = pdev;
return 0;
}
+
+static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *chip,
+ struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
+{
+ struct pnp_dev *pdev;
+ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+
+ if (!cfg)
+ return -ENOMEM;
+ pdev = pnp_request_card_device(card, id->devs[0].id, NULL);
+ if (pdev == NULL) {
+ kfree(cfg);
+ return -EBUSY;
+ }
+ return snd_opl3sa2_pnp(dev, chip, pdev, 1);
+}
#endif /* CONFIG_PNP */
static int snd_opl3sa2_free(opl3sa2_t *chip)
@@ -645,6 +669,7 @@ static int snd_opl3sa2_dev_free(snd_device_t *device)
}
static int __devinit snd_opl3sa2_probe(int dev,
+ struct pnp_dev *pdev,
struct pnp_card_link *pcard,
const struct pnp_card_device_id *pid)
{
@@ -695,8 +720,13 @@ static int __devinit snd_opl3sa2_probe(int dev,
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
goto __error;
#ifdef CONFIG_PNP
- if (isapnp[dev]) {
- if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0)
+ if (pdev) {
+ if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0)
+ goto __error;
+ snd_card_set_dev(card, &pdev->dev);
+ }
+ if (pcard) {
+ if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0)
goto __error;
snd_card_set_dev(card, &pcard->card->dev);
}
@@ -768,7 +798,9 @@ static int __devinit snd_opl3sa2_probe(int dev,
if ((err = snd_card_register(card)) < 0)
goto __error;
- if (pcard)
+ if (pdev)
+ pnp_set_drvdata(pdev, card);
+ else if (pcard)
pnp_set_card_drvdata(pcard, card);
else
snd_opl3sa2_legacy[dev] = card;
@@ -780,8 +812,8 @@ static int __devinit snd_opl3sa2_probe(int dev,
}
#ifdef CONFIG_PNP
-static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
- const struct pnp_card_device_id *id)
+static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
{
static int dev;
int res;
@@ -789,7 +821,7 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
for ( ; dev < SNDRV_CARDS; dev++) {
if (!enable[dev] || !isapnp[dev])
continue;
- res = snd_opl3sa2_probe(dev, card, id);
+ res = snd_opl3sa2_probe(dev, pdev, NULL, NULL);
if (res < 0)
return res;
dev++;
@@ -798,7 +830,40 @@ static int __devinit snd_opl3sa2_pnp_detect(struct pnp_card_link *card,
return -ENODEV;
}
-static void __devexit snd_opl3sa2_pnp_remove(struct pnp_card_link * pcard)
+static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev)
+{
+ snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev);
+
+ snd_card_disconnect(card);
+ snd_card_free_in_thread(card);
+}
+
+static struct pnp_driver opl3sa2_pnp_driver = {
+ .name = "opl3sa2-pnpbios",
+ .id_table = snd_opl3sa2_pnpbiosids,
+ .probe = snd_opl3sa2_pnp_detect,
+ .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+};
+
+static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card,
+ const struct pnp_card_device_id *id)
+{
+ static int dev;
+ int res;
+
+ for ( ; dev < SNDRV_CARDS; dev++) {
+ if (!enable[dev] || !isapnp[dev])
+ continue;
+ res = snd_opl3sa2_probe(dev, NULL, card, id);
+ if (res < 0)
+ return res;
+ dev++;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard)
{
snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
@@ -810,8 +875,8 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = {
.flags = PNP_DRIVER_RES_DISABLE,
.name = "opl3sa2",
.id_table = snd_opl3sa2_pnpids,
- .probe = snd_opl3sa2_pnp_detect,
- .remove = __devexit_p(snd_opl3sa2_pnp_remove),
+ .probe = snd_opl3sa2_pnp_cdetect,
+ .remove = __devexit_p(snd_opl3sa2_pnp_cremove),
};
#endif /* CONFIG_PNP */
@@ -826,10 +891,11 @@ static int __init alsa_card_opl3sa2_init(void)
if (isapnp[dev])
continue;
#endif
- if (snd_opl3sa2_probe(dev, NULL, NULL) >= 0)
+ if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0)
cards++;
}
#ifdef CONFIG_PNP
+ cards += pnp_register_driver(&opl3sa2_pnp_driver);
cards += pnp_register_card_driver(&opl3sa2_pnpc_driver);
#endif
if (!cards) {
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 4afc4a1bc140..26e693078cb3 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -128,7 +128,7 @@ snd_emu8000_write_wait(emu8000_t *emu)
* This is therefore much slower than need be, but is at least
* working.
*/
-inline static void
+static inline void
write_word(emu8000_t *emu, int *offset, unsigned short data)
{
if (emu8000_reset_addr) {
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index a6a0fa516268..a99e642a68b5 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -729,7 +729,7 @@ static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
static snd_kcontrol_new_t snd_sb16_dma_control = {
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
.name = "16-bit DMA Allocation",
.info = snd_sb16_dma_control_info,
.get = snd_sb16_dma_control_get,
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index cc5a2c6dec16..ff4b59968027 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -688,7 +688,7 @@ static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch =
SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
static struct sbmix_elem snd_als4000_ctl_3d_delay =
SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
-#if NOT_AVAILABLE
+#ifdef NOT_AVAILABLE
static struct sbmix_elem snd_als4000_ctl_fmdac =
SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
static struct sbmix_elem snd_als4000_ctl_qsound =
@@ -723,7 +723,7 @@ static struct sbmix_elem *snd_als4000_controls[] = {
&snd_als4000_ctl_3d_output_ratio,
&snd_als4000_ctl_3d_delay,
&snd_als4000_ctl_3d_poweroff_switch,
-#if NOT_AVAILABLE
+#ifdef NOT_AVAILABLE
&snd_als4000_ctl_fmdac,
&snd_als4000_ctl_qsound,
#endif
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 0e13623f69f0..32379688eed4 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -34,7 +34,7 @@
/* weird stuff, derived from port I/O tracing with dosemu */
-unsigned char page_zero[] __initdata = {
+static unsigned char page_zero[] __initdata = {
0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
@@ -61,7 +61,7 @@ unsigned char page_zero[] __initdata = {
0x1d, 0x02, 0xdf
};
-unsigned char page_one[] __initdata = {
+static unsigned char page_one[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
@@ -88,7 +88,7 @@ unsigned char page_one[] __initdata = {
0x60, 0x00, 0x1b
};
-unsigned char page_two[] __initdata = {
+static unsigned char page_two[] __initdata = {
0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -103,7 +103,7 @@ unsigned char page_two[] __initdata = {
0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
};
-unsigned char page_three[] __initdata = {
+static unsigned char page_three[] __initdata = {
0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -118,7 +118,7 @@ unsigned char page_three[] __initdata = {
0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
};
-unsigned char page_four[] __initdata = {
+static unsigned char page_four[] __initdata = {
0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -133,7 +133,7 @@ unsigned char page_four[] __initdata = {
0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
};
-unsigned char page_six[] __initdata = {
+static unsigned char page_six[] __initdata = {
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
@@ -154,7 +154,7 @@ unsigned char page_six[] __initdata = {
0x80, 0x00, 0x7e, 0x80, 0x80
};
-unsigned char page_seven[] __initdata = {
+static unsigned char page_seven[] __initdata = {
0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
@@ -181,7 +181,7 @@ unsigned char page_seven[] __initdata = {
0x00, 0x02, 0x00
};
-unsigned char page_zero_v2[] __initdata = {
+static unsigned char page_zero_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -193,7 +193,7 @@ unsigned char page_zero_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char page_one_v2[] __initdata = {
+static unsigned char page_one_v2[] __initdata = {
0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -205,21 +205,21 @@ unsigned char page_one_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char page_two_v2[] __initdata = {
+static unsigned char page_two_v2[] __initdata = {
0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_three_v2[] __initdata = {
+static unsigned char page_three_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_four_v2[] __initdata = {
+static unsigned char page_four_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -227,7 +227,7 @@ unsigned char page_four_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00
};
-unsigned char page_seven_v2[] __initdata = {
+static unsigned char page_seven_v2[] __initdata = {
0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -239,7 +239,7 @@ unsigned char page_seven_v2[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned char mod_v2[] __initdata = {
+static unsigned char mod_v2[] __initdata = {
0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
@@ -269,7 +269,7 @@ unsigned char mod_v2[] __initdata = {
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
};
-unsigned char coefficients[] __initdata = {
+static unsigned char coefficients[] __initdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
@@ -305,14 +305,14 @@ unsigned char coefficients[] __initdata = {
0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
0xba
};
-unsigned char coefficients2[] __initdata = {
+static unsigned char coefficients2[] __initdata = {
0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
};
-unsigned char coefficients3[] __initdata = {
+static unsigned char coefficients3[] __initdata = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 7bd95ceab7cc..953e5f3ea03d 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -6,7 +6,7 @@
# Prompt user for primary drivers.
config SOUND_BT878
tristate "BT878 audio dma"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && PCI
---help---
Audio DMA support for bt878 based grabber boards. As you might have
already noticed, bt878 is listed with two functions in /proc/pci.
@@ -80,14 +80,14 @@ config SOUND_EMU10K1
config MIDI_EMU10K1
bool "Creative SBLive! MIDI (EXPERIMENTAL)"
- depends on SOUND_EMU10K1 && EXPERIMENTAL
+ depends on SOUND_EMU10K1 && EXPERIMENTAL && ISA_DMA_API
help
Say Y if you want to be able to use the OSS /dev/sequencer
interface. This code is still experimental.
config SOUND_FUSION
tristate "Crystal SoundFusion (CS4280/461x)"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && PCI
help
This module drives the Crystal SoundFusion devices (CS4280/46xx
series) when wired as native sound drivers with AC97 codecs. If
@@ -95,7 +95,7 @@ config SOUND_FUSION
config SOUND_CS4281
tristate "Crystal Sound CS4281"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && PCI
help
Picture and feature list at
<http://www.pcbroker.com/crystal4281.html>.
@@ -179,7 +179,7 @@ config SOUND_HARMONY
config SOUND_SONICVIBES
tristate "S3 SonicVibes"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a PCI sound card utilizing the S3
SonicVibes chipset. To find out if your sound card uses a
@@ -226,7 +226,7 @@ config SOUND_AU1550_AC97
config SOUND_TRIDENT
tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && PCI
---help---
Say Y or M if you have a PCI sound card utilizing the Trident
4DWave-DX/NX chipset or your mother board chipset has SiS 7018
@@ -503,7 +503,7 @@ config SOUND_VIA82CXXX
config MIDI_VIA82CXXX
bool "VIA 82C686 MIDI"
- depends on SOUND_VIA82CXXX
+ depends on SOUND_VIA82CXXX && ISA_DMA_API
help
Answer Y to use the MIDI interface of the Via686. You may need to
enable this in the BIOS before it will work. This is for connection
@@ -512,7 +512,7 @@ config MIDI_VIA82CXXX
config SOUND_OSS
tristate "OSS sound modules"
- depends on SOUND_PRIME
+ depends on SOUND_PRIME && ISA_DMA_API
help
OSS is the Open Sound System suite of sound card drivers. They make
sound programming easier since they provide a common API. Say Y or
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index db9afb61d6ff..9bf3ee544d86 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -80,7 +80,7 @@ obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o
obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o
obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o
-obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o
+obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
ifeq ($(CONFIG_MIDI_EMU10K1),y)
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 2704e1598add..2ceb46f1d40f 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -1557,7 +1557,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
/* All the burgundy functions: */
/* Waits for busy flag to clear */
-inline static void
+static inline void
awacs_burgundy_busy_wait(void)
{
int count = 50; /* > 2 samples at 44k1 */
@@ -1565,7 +1565,7 @@ awacs_burgundy_busy_wait(void)
udelay(1) ;
}
-inline static void
+static inline void
awacs_burgundy_extend_wait(void)
{
int count = 50 ; /* > 2 samples at 44k1 */
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
index 7e9f667cf7a7..b9a640fe48b1 100644
--- a/sound/oss/i810_audio.c
+++ b/sound/oss/i810_audio.c
@@ -3430,9 +3430,9 @@ out_iospace:
release_mem_region(card->iobase_mmio_phys, 256);
}
out_pio:
- release_region(card->iobase, 64);
-out_region2:
release_region(card->ac97base, 256);
+out_region2:
+ release_region(card->iobase, 64);
out_region1:
pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
card->channel, card->chandma);
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index 3ed38765dcc4..a617ccb40e00 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -714,7 +714,7 @@ static int __init attach_pss(struct address_info *hw_config)
disable_all_emulations();
-#if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES
+#ifdef YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES
if (sound_alloc_dma(hw_config->dma, "PSS"))
{
printk("pss.c: Can't allocate DMA channel.\n");
diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h
index bab7044572d3..d5b8064dc565 100644
--- a/sound/oss/vidc.h
+++ b/sound/oss/vidc.h
@@ -10,10 +10,6 @@
* VIDC sound function prototypes
*/
-/* vidc.c */
-
-extern int vidc_busy;
-
/* vidc_fill.S */
/*
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 6d7a00f34d82..1e458919cce6 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -1,11 +1,15 @@
# ALSA PCI drivers
-menu "PCI devices"
- depends on SND!=n && PCI
-
config SND_AC97_CODEC
tristate
select SND_PCM
+ select SND_AC97_BUS
+
+config SND_AC97_BUS
+ tristate
+
+menu "PCI devices"
+ depends on SND!=n && PCI
config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
@@ -314,7 +318,7 @@ config SND_YMFPCI
config SND_ALS4000
tristate "Avance Logic ALS4000"
- depends on SND
+ depends on SND && ISA_DMA_API
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile
index 3c3222122d8b..77b3482cb133 100644
--- a/sound/pci/ac97/Makefile
+++ b/sound/pci/ac97/Makefile
@@ -10,9 +10,11 @@ snd-ac97-codec-objs += ac97_proc.o
endif
snd-ak4531-codec-objs := ak4531_codec.o
+snd-ac97-bus-objs := ac97_bus.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o
obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o
+obj-$(CONFIG_SND_AC97_BUS) += snd-ac97-bus.o
obj-m := $(sort $(obj-m))
diff --git a/sound/pci/ac97/ac97_bus.c b/sound/pci/ac97/ac97_bus.c
new file mode 100644
index 000000000000..227f8b9f67ce
--- /dev/null
+++ b/sound/pci/ac97/ac97_bus.c
@@ -0,0 +1,79 @@
+/*
+ * Linux driver model AC97 bus interface
+ *
+ * Author: Nicolas Pitre
+ * Created: Jan 14, 2005
+ * Copyright: (C) MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+/*
+ * Codec families have names seperated by commas, so we search for an
+ * individual codec name within the family string.
+ */
+static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+{
+ return (strstr(dev->bus_id, drv->name) != NULL);
+}
+
+static int ac97_bus_suspend(struct device *dev, pm_message_t state)
+{
+ int ret = 0;
+
+ if (dev->driver && dev->driver->suspend) {
+ ret = dev->driver->suspend(dev, state, SUSPEND_DISABLE);
+ if (ret == 0)
+ ret = dev->driver->suspend(dev, state, SUSPEND_SAVE_STATE);
+ if (ret == 0)
+ ret = dev->driver->suspend(dev, state, SUSPEND_POWER_DOWN);
+ }
+ return ret;
+}
+
+static int ac97_bus_resume(struct device *dev)
+{
+ int ret = 0;
+
+ if (dev->driver && dev->driver->resume) {
+ ret = dev->driver->resume(dev, RESUME_POWER_ON);
+ if (ret == 0)
+ ret = dev->driver->resume(dev, RESUME_RESTORE_STATE);
+ if (ret == 0)
+ ret = dev->driver->resume(dev, RESUME_ENABLE);
+ }
+ return ret;
+}
+
+struct bus_type ac97_bus_type = {
+ .name = "ac97",
+ .match = ac97_bus_match,
+ .suspend = ac97_bus_suspend,
+ .resume = ac97_bus_resume,
+};
+
+static int __init ac97_bus_init(void)
+{
+ return bus_register(&ac97_bus_type);
+}
+
+subsys_initcall(ac97_bus_init);
+
+static void __exit ac97_bus_exit(void)
+{
+ bus_unregister(&ac97_bus_type);
+}
+
+module_exit(ac97_bus_exit);
+
+EXPORT_SYMBOL(ac97_bus_type);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index a4b72cd2eea0..5501f4440c92 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -157,6 +157,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
+{ 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF
{ 0x57454301, 0xffffffff, "W83971D", NULL, NULL },
{ 0x574d4c00, 0xffffffff, "WM9701A", NULL, NULL },
{ 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -367,6 +368,7 @@ int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
ac97->regs[reg] = value;
ac97->bus->ops->write(ac97, reg, value);
}
+ set_bit(reg, ac97->reg_accessed);
up(&ac97->reg_mutex);
return change;
}
@@ -410,6 +412,7 @@ int snd_ac97_update_bits_nolock(ac97_t *ac97, unsigned short reg,
ac97->regs[reg] = new;
ac97->bus->ops->write(ac97, reg, new);
}
+ set_bit(reg, ac97->reg_accessed);
return change;
}
@@ -1076,6 +1079,11 @@ static void check_volume_resolution(ac97_t *ac97, int reg, unsigned char *lo_max
for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
unsigned short val;
snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
+ /* Do the read twice due to buffers on some ac97 codecs.
+ * e.g. The STAC9704 returns exactly what you wrote the the register
+ * if you read it immediately. This causes the detect routine to fail.
+ */
+ val = snd_ac97_read(ac97, reg);
val = snd_ac97_read(ac97, reg);
if (! *lo_max && (val & 0x7f) == cbit[i])
*lo_max = max[i];
@@ -1300,16 +1308,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
/* build master tone controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
- for (idx = 0; idx < 2; idx++) {
- if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
- return err;
- if (ac97->id == AC97_ID_YMF753) {
- kctl->private_value &= ~(0xff << 16);
- kctl->private_value |= 7 << 16;
+ if (!(ac97->flags & AC97_HAS_NO_TONE)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
+ for (idx = 0; idx < 2; idx++) {
+ if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
+ return err;
+ if (ac97->id == AC97_ID_YMF753) {
+ kctl->private_value &= ~(0xff << 16);
+ kctl->private_value |= 7 << 16;
+ }
}
+ snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
}
- snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
}
/* build PC Speaker controls */
@@ -1332,11 +1342,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
/* build MIC controls */
- if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
- if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
- return err;
- if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
- return err;
+ if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+ if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+ if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
+ return err;
+ if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+ return err;
+ }
}
/* build Line controls */
@@ -1395,12 +1407,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
}
snd_ac97_write_cache(ac97, AC97_PCM, init_val);
} else {
- if (ac97->flags & AC97_HAS_NO_PCM_VOL)
- err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
- else
- err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
- if (err < 0)
- return err;
+ if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+ if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+ err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
+ else
+ err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
+ if (err < 0)
+ return err;
+ }
}
/* build Capture controls */
@@ -1800,6 +1814,39 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
return 0;
}
+/* stop no dev release warning */
+static void ac97_device_release(struct device * dev)
+{
+}
+
+/* register ac97 codec to bus */
+static int snd_ac97_dev_register(snd_device_t *device)
+{
+ ac97_t *ac97 = device->device_data;
+ int err;
+
+ ac97->dev.bus = &ac97_bus_type;
+ ac97->dev.parent = ac97->bus->card->dev;
+ ac97->dev.platform_data = ac97;
+ ac97->dev.release = ac97_device_release;
+ snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
+ if ((err = device_register(&ac97->dev)) < 0) {
+ snd_printk(KERN_ERR "Can't register ac97 bus\n");
+ ac97->dev.bus = NULL;
+ return err;
+ }
+ return 0;
+}
+
+/* unregister ac97 codec */
+static int snd_ac97_dev_unregister(snd_device_t *device)
+{
+ ac97_t *ac97 = device->device_data;
+ if (ac97->dev.bus)
+ device_unregister(&ac97->dev);
+ return snd_ac97_free(ac97);
+}
+
/* build_ops to do nothing */
static struct snd_ac97_build_ops null_build_ops;
@@ -1833,6 +1880,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
const ac97_codec_id_t *pid;
static snd_device_ops_t ops = {
.dev_free = snd_ac97_dev_free,
+ .dev_register = snd_ac97_dev_register,
+ .dev_unregister = snd_ac97_dev_unregister,
};
snd_assert(rac97 != NULL, return -EINVAL);
@@ -2224,7 +2273,7 @@ void snd_ac97_restore_iec958(ac97_t *ac97)
*/
void snd_ac97_resume(ac97_t *ac97)
{
- int i;
+ unsigned long end_time;
if (ac97->bus->ops->reset) {
ac97->bus->ops->reset(ac97);
@@ -2242,26 +2291,26 @@ void snd_ac97_resume(ac97_t *ac97)
snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
if (ac97_is_audio(ac97)) {
ac97->bus->ops->write(ac97, AC97_MASTER, 0x8101);
- for (i = HZ/10; i >= 0; i--) {
+ end_time = jiffies + msecs_to_jiffies(100);
+ do {
if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- }
+ } while (time_after_eq(end_time, jiffies));
/* FIXME: extra delay */
ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000);
- if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
- }
+ if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000)
+ msleep(250);
} else {
- for (i = HZ/10; i >= 0; i--) {
+ end_time = jiffies + msecs_to_jiffies(100);
+ do {
unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
if (val != 0xffff && (val & 1) != 0)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- }
+ } while (time_after_eq(end_time, jiffies));
}
__reset_ready:
@@ -2532,8 +2581,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
{
int result;
- snd_assert(quirk, return -EINVAL);
-
/* quirk overriden? */
if (override && strcmp(override, "-1") && strcmp(override, "default")) {
result = apply_quirk_str(ac97, override);
@@ -2542,6 +2589,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
return result;
}
+ if (! quirk)
+ return -EINVAL;
+
for (; quirk->subvendor; quirk++) {
if (quirk->subvendor != ac97->subsystem_vendor)
continue;
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index a15eb8522b7c..b584172c1104 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -370,141 +370,387 @@ int patch_yamaha_ymf753(ac97_t * ac97)
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717.
*/
-int patch_wolfson03(ac97_t * ac97)
+static const snd_kcontrol_new_t wm97xx_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+};
+
+static int patch_wolfson_wm9703_specific(ac97_t * ac97)
{
/* This is known to work for the ViewSonic ViewPad 1000
- Randolph Bentson <bentson@holmsjoen.com> */
+ * Randolph Bentson <bentson@holmsjoen.com>
+ * WM9703/9707/9708/9717
+ */
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
+ return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = {
+ .build_specific = patch_wolfson_wm9703_specific,
+};
- // WM9703/9707/9708/9717
- snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
- snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x8000);
+int patch_wolfson03(ac97_t * ac97)
+{
+ ac97->build_ops = &patch_wolfson_wm9703_ops;
return 0;
}
-
-int patch_wolfson04(ac97_t * ac97)
+
+static const snd_kcontrol_new_t wm9704_snd_ac97_controls[] = {
+AC97_DOUBLE("Front Playback Volume", AC97_WM97XX_FMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Front Playback Switch", AC97_WM97XX_FMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear Playback Volume", AC97_WM9704_RMIXER_VOL, 8, 0, 31, 1),
+AC97_SINGLE("Rear Playback Switch", AC97_WM9704_RMIXER_VOL, 15, 1, 1),
+AC97_DOUBLE("Rear DAC Volume", AC97_WM9704_RPCM_VOL, 8, 0, 31, 1),
+AC97_DOUBLE("Surround Volume", AC97_SURROUND_MASTER, 8, 0, 31, 1),
+};
+
+static int patch_wolfson_wm9704_specific(ac97_t * ac97)
{
- // WM9704M/9704Q
- // set front and rear mixer volume
- snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
- snd_ac97_write_cache(ac97, AC97_WM9704_RMIXER_VOL, 0x0808);
-
- // patch for DVD noise
+ int err, i;
+ for (i = 0; i < ARRAY_SIZE(wm9704_snd_ac97_controls); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9704_snd_ac97_controls[i], ac97))) < 0)
+ return err;
+ }
+ /* patch for DVD noise */
snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200);
-
- // init vol
- snd_ac97_write_cache(ac97, AC97_WM9704_RPCM_VOL, 0x0808);
-
- // set rear surround volume
- snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
return 0;
}
-
+
+static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = {
+ .build_specific = patch_wolfson_wm9704_specific,
+};
+
+int patch_wolfson04(ac97_t * ac97)
+{
+ /* WM9704M/9704Q */
+ ac97->build_ops = &patch_wolfson_wm9704_ops;
+ return 0;
+}
+
+static int patch_wolfson_wm9705_specific(ac97_t * ac97)
+{
+ int err, i;
+ for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, 0x72, 0x0808);
+ return 0;
+}
+
+static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = {
+ .build_specific = patch_wolfson_wm9705_specific,
+};
+
int patch_wolfson05(ac97_t * ac97)
{
- // WM9705, WM9710
- // set front mixer volume
- snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808);
+ /* WM9705, WM9710 */
+ ac97->build_ops = &patch_wolfson_wm9705_ops;
+ return 0;
+}
+
+static const char* wm9711_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9711_alc_mix[] = {"Stereo", "Right", "Left", "None"};
+static const char* wm9711_out3_src[] = {"Left", "VREF", "Left + Right", "Mono"};
+static const char* wm9711_out3_lrsrc[] = {"Master Mix", "Headphone Mix"};
+static const char* wm9711_rec_adc[] = {"Stereo", "Left", "Right", "Mute"};
+static const char* wm9711_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9711_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9711_mic[] = {"Mic 1", "Differential", "Mic 2", "Stereo"};
+static const char* wm9711_rec_sel[] =
+ {"Mic 1", "NC", "NC", "Master Mix", "Line", "Headphone Mix", "Phone Mix", "Phone"};
+static const char* wm9711_ng_type[] = {"Constant Gain", "Mute"};
+
+static const struct ac97_enum wm9711_enum[] = {
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9711_alc_select),
+AC97_ENUM_SINGLE(AC97_VIDEO, 10, 4, wm9711_alc_mix),
+AC97_ENUM_SINGLE(AC97_AUX, 9, 4, wm9711_out3_src),
+AC97_ENUM_SINGLE(AC97_AUX, 8, 2, wm9711_out3_lrsrc),
+AC97_ENUM_SINGLE(AC97_REC_SEL, 12, 4, wm9711_rec_adc),
+AC97_ENUM_SINGLE(AC97_MASTER_TONE, 15, 2, wm9711_base),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 14, 6, 2, wm9711_rec_gain),
+AC97_ENUM_SINGLE(AC97_MIC, 5, 4, wm9711_mic),
+AC97_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, wm9711_rec_sel),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9711_ng_type),
+};
+
+static const snd_kcontrol_new_t wm9711_snd_ac97_controls[] = {
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9711_enum[0]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 1),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 1),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9711_enum[9]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 1),
+
+AC97_SINGLE("Side Tone Switch", AC97_VIDEO, 15, 1, 1),
+AC97_SINGLE("Side Tone Volume", AC97_VIDEO, 12, 7, 1),
+AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]),
+AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
+
+AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+AC97_ENUM("Out3 Mux", wm9711_enum[2]),
+AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
+AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
+
+AC97_SINGLE("Beep to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Beep to Headphone Volume", AC97_PC_BEEP, 12, 7, 1),
+AC97_SINGLE("Beep to Side Tone Switch", AC97_PC_BEEP, 11, 1, 1),
+AC97_SINGLE("Beep to Side Tone Volume", AC97_PC_BEEP, 8, 7, 1),
+AC97_SINGLE("Beep to Phone Switch", AC97_PC_BEEP, 7, 1, 1),
+AC97_SINGLE("Beep to Phone Volume", AC97_PC_BEEP, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_CD, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_CD, 12, 7, 1),
+AC97_SINGLE("Aux to Side Tone Switch", AC97_CD, 11, 1, 1),
+AC97_SINGLE("Aux to Side Tone Volume", AC97_CD, 8, 7, 1),
+AC97_SINGLE("Aux to Phone Switch", AC97_CD, 7, 1, 1),
+AC97_SINGLE("Aux to Phone Volume", AC97_CD, 4, 7, 1),
+
+AC97_SINGLE("Phone to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("Phone to Master Switch", AC97_PHONE, 14, 1, 1),
+
+AC97_SINGLE("Line to Headphone Switch", AC97_LINE, 15, 1, 1),
+AC97_SINGLE("Line to Master Switch", AC97_LINE, 14, 1, 1),
+AC97_SINGLE("Line to Phone Switch", AC97_LINE, 13, 1, 1),
+
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PCM, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Phone Switch", AC97_PCM, 13, 1, 1),
+
+AC97_SINGLE("Capture 20dB Boost Switch", AC97_REC_SEL, 14, 1, 0),
+AC97_ENUM("Capture to Phone Mux", wm9711_enum[4]),
+AC97_SINGLE("Capture to Phone 20dB Boost Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_ENUM("Capture Select", wm9711_enum[8]),
+
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_3D_CONTROL, 5, 1, 1),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_3D_CONTROL, 4, 1, 1),
+
+AC97_ENUM("Bass Control", wm9711_enum[5]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_MASTER_TONE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_MASTER_TONE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
+
+AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
+AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
+AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
+
+AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
+AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
+AC97_ENUM("Mic Select Source", wm9711_enum[7]),
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
+AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
+
+AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
+AC97_SINGLE("Headphone ZC Switch", AC97_HEADPHONE, 7, 1, 0),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_MONO, 7, 1, 0),
+};
+
+static int patch_wolfson_wm9711_specific(ac97_t * ac97)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm9711_snd_ac97_controls); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm9711_snd_ac97_controls[i], ac97))) < 0)
+ return err;
+ }
+ snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_PCI_SVID, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_VIDEO, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_AUX, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
+ snd_ac97_write_cache(ac97, AC97_CD, 0x0000);
return 0;
}
+static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = {
+ .build_specific = patch_wolfson_wm9711_specific,
+};
+
int patch_wolfson11(ac97_t * ac97)
{
- // WM9711, WM9712
- // set out3 volume
- snd_ac97_write_cache(ac97, AC97_WM9711_OUT3VOL, 0x0808);
+ /* WM9711, WM9712 */
+ ac97->build_ops = &patch_wolfson_wm9711_ops;
+
+ ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_MIC |
+ AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+
return 0;
}
-static const char* wm9713_mic_mixer[] = {"Stereo", "Mic1", "Mic2", "Mute"};
+static const char* wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
static const char* wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
-static const char* wm9713_rec_src_l[] = {"Mic1", "Mic2", "Line L", "Mono In", "HP Mix L", "Spk Mix", "Mono Mix", "Zh"};
-static const char* wm9713_rec_src_r[] = {"Mic1", "Mic2", "Line R", "Mono In", "HP Mix R", "Spk Mix", "Mono Mix", "Zh"};
+static const char* wm9713_rec_src[] =
+ {"Mic 1", "Mic 2", "Line", "Mono In", "Headphone Mix", "Master Mix",
+ "Mono Mix", "Zh"};
+static const char* wm9713_rec_gain[] = {"+1.5dB Steps", "+0.75dB Steps"};
+static const char* wm9713_alc_select[] = {"None", "Left", "Right", "Stereo"};
+static const char* wm9713_mono_pga[] = {"Vmid", "Zh", "Mono Mix", "Inv 1"};
+static const char* wm9713_spk_pga[] =
+ {"Vmid", "Zh", "Headphone Mix", "Master Mix", "Inv", "NC", "NC", "NC"};
+static const char* wm9713_hp_pga[] = {"Vmid", "Zh", "Headphone Mix", "NC"};
+static const char* wm9713_out3_pga[] = {"Vmid", "Zh", "Inv 1", "NC"};
+static const char* wm9713_out4_pga[] = {"Vmid", "Zh", "Inv 2", "NC"};
+static const char* wm9713_dac_inv[] =
+ {"Off", "Mono Mix", "Master Mix", "Headphone Mix L", "Headphone Mix R",
+ "Headphone Mix Mono", "NC", "Vmid"};
+static const char* wm9713_base[] = {"Linear Control", "Adaptive Boost"};
+static const char* wm9713_ng_type[] = {"Constant Gain", "Mute"};
static const struct ac97_enum wm9713_enum[] = {
AC97_ENUM_SINGLE(AC97_LINE, 3, 4, wm9713_mic_mixer),
AC97_ENUM_SINGLE(AC97_VIDEO, 14, 4, wm9713_rec_mux),
AC97_ENUM_SINGLE(AC97_VIDEO, 9, 4, wm9713_rec_mux),
-AC97_ENUM_SINGLE(AC97_VIDEO, 3, 8, wm9713_rec_src_l),
-AC97_ENUM_SINGLE(AC97_VIDEO, 0, 8, wm9713_rec_src_r),
+AC97_ENUM_DOUBLE(AC97_VIDEO, 3, 0, 8, wm9713_rec_src),
+AC97_ENUM_DOUBLE(AC97_CD, 14, 6, 2, wm9713_rec_gain),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 14, 4, wm9713_alc_select),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 14, 4, wm9713_mono_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 11, 8, 8, wm9713_spk_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN, 6, 4, 4, wm9713_hp_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 2, 4, wm9713_out3_pga),
+AC97_ENUM_SINGLE(AC97_REC_GAIN, 0, 4, wm9713_out4_pga),
+AC97_ENUM_DOUBLE(AC97_REC_GAIN_MIC, 13, 10, 8, wm9713_dac_inv),
+AC97_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_base),
+AC97_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type),
};
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_line_in[] = {
+static const snd_kcontrol_new_t wm13_snd_ac97_controls[] = {
AC97_DOUBLE("Line In Volume", AC97_PC_BEEP, 8, 0, 31, 1),
-AC97_SINGLE("Line In to Headphone Mute", AC97_PC_BEEP, 15, 1, 1),
-AC97_SINGLE("Line In to Speaker Mute", AC97_PC_BEEP, 14, 1, 1),
-AC97_SINGLE("Line In to Mono Mute", AC97_PC_BEEP, 13, 1, 1),
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_dac[] = {
-AC97_DOUBLE("DAC Volume", AC97_PHONE, 8, 0, 31, 1),
-AC97_SINGLE("DAC to Headphone Mute", AC97_PHONE, 15, 1, 1),
-AC97_SINGLE("DAC to Speaker Mute", AC97_PHONE, 14, 1, 1),
-AC97_SINGLE("DAC to Mono Mute", AC97_PHONE, 13, 1, 1),
-};
-
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_mic[] = {
-AC97_SINGLE("MICA Volume", AC97_MIC, 8, 31, 1),
-AC97_SINGLE("MICB Volume", AC97_MIC, 0, 31, 1),
-AC97_SINGLE("MICA to Mono Mute", AC97_LINE, 7, 1, 1),
-AC97_SINGLE("MICB to Mono Mute", AC97_LINE, 6, 1, 1),
-AC97_SINGLE("MIC Boost (+20dB)", AC97_LINE, 5, 1, 1),
-AC97_ENUM("MIC Headphone Routing", wm9713_enum[0]),
-AC97_SINGLE("MIC Headphone Mixer Volume", AC97_LINE, 0, 7, 1)
+AC97_SINGLE("Line In to Headphone Switch", AC97_PC_BEEP, 15, 1, 1),
+AC97_SINGLE("Line In to Master Switch", AC97_PC_BEEP, 14, 1, 1),
+AC97_SINGLE("Line In to Mono Switch", AC97_PC_BEEP, 13, 1, 1),
+
+AC97_DOUBLE("PCM Playback Volume", AC97_PHONE, 8, 0, 31, 1),
+AC97_SINGLE("PCM Playback to Headphone Switch", AC97_PHONE, 15, 1, 1),
+AC97_SINGLE("PCM Playback to Master Switch", AC97_PHONE, 14, 1, 1),
+AC97_SINGLE("PCM Playback to Mono Switch", AC97_PHONE, 13, 1, 1),
+
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
+AC97_SINGLE("Mic 1 to Mono Switch", AC97_LINE, 7, 1, 1),
+AC97_SINGLE("Mic 2 to Mono Switch", AC97_LINE, 6, 1, 1),
+AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_LINE, 5, 1, 0),
+AC97_ENUM("Mic to Headphone Mux", wm9713_enum[0]),
+AC97_SINGLE("Mic Headphone Mixer Volume", AC97_LINE, 0, 7, 1),
+
+AC97_SINGLE("Capture Switch", AC97_CD, 15, 1, 1),
+AC97_ENUM("Capture Volume Steps", wm9713_enum[4]),
+AC97_DOUBLE("Capture Volume", AC97_CD, 8, 0, 15, 0),
+AC97_SINGLE("Capture ZC Switch", AC97_CD, 7, 1, 0),
+
+AC97_ENUM("Capture to Headphone Mux", wm9713_enum[1]),
+AC97_SINGLE("Capture to Headphone Volume", AC97_VIDEO, 11, 7, 1),
+AC97_ENUM("Capture to Mono Mux", wm9713_enum[2]),
+AC97_SINGLE("Capture to Mono Boost (+20dB) Switch", AC97_VIDEO, 8, 1, 0),
+AC97_SINGLE("Capture ADC Boost (+20dB) Switch", AC97_VIDEO, 6, 1, 0),
+AC97_ENUM("Capture Select", wm9713_enum[3]),
+
+AC97_SINGLE("ALC Target Volume", AC97_CODEC_CLASS_REV, 12, 15, 0),
+AC97_SINGLE("ALC Hold Time", AC97_CODEC_CLASS_REV, 8, 15, 0),
+AC97_SINGLE("ALC Decay Time ", AC97_CODEC_CLASS_REV, 4, 15, 0),
+AC97_SINGLE("ALC Attack Time", AC97_CODEC_CLASS_REV, 0, 15, 0),
+AC97_ENUM("ALC Function", wm9713_enum[5]),
+AC97_SINGLE("ALC Max Volume", AC97_PCI_SVID, 11, 7, 0),
+AC97_SINGLE("ALC ZC Timeout", AC97_PCI_SVID, 9, 3, 0),
+AC97_SINGLE("ALC ZC Switch", AC97_PCI_SVID, 8, 1, 0),
+AC97_SINGLE("ALC NG Switch", AC97_PCI_SVID, 7, 1, 0),
+AC97_ENUM("ALC NG Type", wm9713_enum[13]),
+AC97_SINGLE("ALC NG Threshold", AC97_PCI_SVID, 0, 31, 0),
+
+AC97_DOUBLE("Master ZC Switch", AC97_MASTER, 14, 6, 1, 0),
+AC97_DOUBLE("Headphone ZC Switch", AC97_HEADPHONE, 14, 6, 1, 0),
+AC97_DOUBLE("Out3/4 ZC Switch", AC97_MASTER_MONO, 14, 6, 1, 0),
+AC97_SINGLE("Master Right Switch", AC97_MASTER, 7, 1, 1),
+AC97_SINGLE("Headphone Right Switch", AC97_HEADPHONE, 7, 1, 1),
+AC97_SINGLE("Out3/4 Right Switch", AC97_MASTER_MONO, 7, 1, 1),
+
+AC97_SINGLE("Mono In to Headphone Switch", AC97_MASTER_TONE, 15, 1, 1),
+AC97_SINGLE("Mono In to Master Switch", AC97_MASTER_TONE, 14, 1, 1),
+AC97_SINGLE("Mono In Volume", AC97_MASTER_TONE, 8, 31, 1),
+AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1),
+AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0),
+AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1),
+
+AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1),
+AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1),
+AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1),
+AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1),
+AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1),
+AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1),
+
+AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1),
+AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1),
+AC97_SINGLE("Voice to Master Switch", AC97_PCM, 11, 1, 1),
+AC97_SINGLE("Voice to Master Volume", AC97_PCM, 8, 7, 1),
+AC97_SINGLE("Voice to Mono Switch", AC97_PCM, 7, 1, 1),
+AC97_SINGLE("Voice to Mono Volume", AC97_PCM, 4, 7, 1),
+
+AC97_SINGLE("Aux to Headphone Switch", AC97_REC_SEL, 15, 1, 1),
+AC97_SINGLE("Aux to Headphone Volume", AC97_REC_SEL, 12, 7, 1),
+AC97_SINGLE("Aux to Master Switch", AC97_REC_SEL, 11, 1, 1),
+AC97_SINGLE("Aux to Master Volume", AC97_REC_SEL, 8, 7, 1),
+AC97_SINGLE("Aux to Mono Switch", AC97_REC_SEL, 7, 1, 1),
+AC97_SINGLE("Aux to Mono Volume", AC97_REC_SEL, 4, 7, 1),
+
+AC97_ENUM("Mono Input Mux", wm9713_enum[6]),
+AC97_ENUM("Master Input Mux", wm9713_enum[7]),
+AC97_ENUM("Headphone Input Mux", wm9713_enum[8]),
+AC97_ENUM("Out 3 Input Mux", wm9713_enum[9]),
+AC97_ENUM("Out 4 Input Mux", wm9713_enum[10]),
+
+AC97_ENUM("Bass Control", wm9713_enum[12]),
+AC97_SINGLE("Bass Cut-off Switch", AC97_GENERAL_PURPOSE, 12, 1, 1),
+AC97_SINGLE("Tone Cut-off Switch", AC97_GENERAL_PURPOSE, 4, 1, 1),
+AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_GENERAL_PURPOSE, 6, 1, 0),
+AC97_SINGLE("Bass Volume", AC97_GENERAL_PURPOSE, 8, 15, 1),
+AC97_SINGLE("Tone Volume", AC97_GENERAL_PURPOSE, 0, 15, 1),
};
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_adc[] = {
-AC97_SINGLE("ADC Mute", AC97_CD, 15, 1, 1),
-AC97_DOUBLE("Gain Step Size (1.5dB/0.75dB)", AC97_CD, 14, 6, 1, 1),
-AC97_DOUBLE("ADC Volume",AC97_CD, 8, 0, 15, 0),
-AC97_SINGLE("ADC Zero Cross", AC97_CD, 7, 1, 1),
+static const snd_kcontrol_new_t wm13_snd_ac97_controls_3d[] = {
+AC97_ENUM("Inv Input Mux", wm9713_enum[11]),
+AC97_SINGLE("3D Upper Cut-off Switch", AC97_REC_GAIN_MIC, 5, 1, 0),
+AC97_SINGLE("3D Lower Cut-off Switch", AC97_REC_GAIN_MIC, 4, 1, 0),
+AC97_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
};
-static const snd_kcontrol_new_t wm13_snd_ac97_controls_recsel[] = {
-AC97_ENUM("Record to Headphone Path", wm9713_enum[1]),
-AC97_SINGLE("Record to Headphone Volume", AC97_VIDEO, 11, 7, 0),
-AC97_ENUM("Record to Mono Path", wm9713_enum[2]),
-AC97_SINGLE("Record to Mono Boost (+20dB)", AC97_VIDEO, 8, 1, 0),
-AC97_SINGLE("Record ADC Boost (+20dB)", AC97_VIDEO, 6, 1, 0),
-AC97_ENUM("Record Select Left", wm9713_enum[3]),
-AC97_ENUM("Record Select Right", wm9713_enum[4]),
-};
+static int patch_wolfson_wm9713_3d (ac97_t * ac97)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_3d); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_3d[i], ac97))) < 0)
+ return err;
+ }
+ return 0;
+}
static int patch_wolfson_wm9713_specific(ac97_t * ac97)
{
int err, i;
- for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_line_in); i++) {
- if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_line_in[i], ac97))) < 0)
+ for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls); i++) {
+ if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls[i], ac97))) < 0)
return err;
}
snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x0808);
-
- for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_dac); i++) {
- if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_dac[i], ac97))) < 0)
- return err;
- }
snd_ac97_write_cache(ac97, AC97_PHONE, 0x0808);
-
- for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_mic); i++) {
- if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_mic[i], ac97))) < 0)
- return err;
- }
snd_ac97_write_cache(ac97, AC97_MIC, 0x0808);
snd_ac97_write_cache(ac97, AC97_LINE, 0x00da);
-
- for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_adc); i++) {
- if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_adc[i], ac97))) < 0)
- return err;
- }
snd_ac97_write_cache(ac97, AC97_CD, 0x0808);
-
- for (i = 0; i < ARRAY_SIZE(wm13_snd_ac97_controls_recsel); i++) {
- if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm13_snd_ac97_controls_recsel[i], ac97))) < 0)
- return err;
- }
snd_ac97_write_cache(ac97, AC97_VIDEO, 0xd612);
snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x1ba0);
-
return 0;
}
@@ -525,6 +771,7 @@ static void patch_wolfson_wm9713_resume (ac97_t * ac97)
static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
.build_specific = patch_wolfson_wm9713_specific,
+ .build_3d = patch_wolfson_wm9713_3d,
#ifdef CONFIG_PM
.suspend = patch_wolfson_wm9713_suspend,
.resume = patch_wolfson_wm9713_resume
@@ -533,10 +780,13 @@ static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = {
int patch_wolfson13(ac97_t * ac97)
{
+ /* WM9713, WM9714 */
ac97->build_ops = &patch_wolfson_wm9713_ops;
ac97->flags |= AC97_HAS_NO_REC_GAIN | AC97_STEREO_MUTES | AC97_HAS_NO_PHONE |
- AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD;
+ AC97_HAS_NO_PC_BEEP | AC97_HAS_NO_VIDEO | AC97_HAS_NO_CD | AC97_HAS_NO_TONE |
+ AC97_HAS_NO_STD_PCM;
+ ac97->scaps &= ~AC97_SCAP_MODEM;
snd_ac97_write_cache(ac97, AC97_EXTENDED_MID, 0xda00);
snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0x3810);
@@ -1379,6 +1629,7 @@ static void check_ad1981_hp_jack_sense(ac97_t *ac97)
u32 subid = ((u32)ac97->subsystem_vendor << 16) | ac97->subsystem_device;
switch (subid) {
case 0x103c0890: /* HP nc6000 */
+ case 0x103c099c: /* HP nx6110 */
case 0x103c006d: /* HP nx9105 */
case 0x17340088: /* FSC Scenic-W */
/* enable headphone jack sense */
@@ -1528,6 +1779,9 @@ static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = {
},
AC97_SURROUND_JACK_MODE_CTL,
AC97_CHANNEL_MODE_CTL,
+
+ AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+ AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
};
static int patch_ad1888_specific(ac97_t *ac97)
@@ -1703,7 +1957,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = {
- AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0),
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
/* disable this controls since it doesn't work as expected */
/* AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), */
@@ -1846,12 +2100,12 @@ static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
}
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
- AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
+ AC97_PAGE_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_ALC650_MULTICH, 11, 1, 0, 0),
/* disable this controls since it doesn't work as expected */
/* AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0), */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Playback Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = alc655_iec958_route_info,
.get = alc655_iec958_route_get,
.put = alc655_iec958_route_put,
@@ -2413,6 +2667,16 @@ int patch_vt1616(ac97_t * ac97)
}
/*
+ * VT1617A codec
+ */
+int patch_vt1617a(ac97_t * ac97)
+{
+ ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */
+ ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000;
+ return 0;
+}
+
+/*
*/
static void it2646_update_jacks(ac97_t *ac97)
{
@@ -2430,7 +2694,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = {
};
static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = {
- AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0),
+ AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0x76, 11, 1, 0),
AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0),
AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0),
};
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 7b7377d0f2ae..ec1811320106 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -56,5 +56,6 @@ int patch_cm9739(ac97_t * ac97);
int patch_cm9761(ac97_t * ac97);
int patch_cm9780(ac97_t * ac97);
int patch_vt1616(ac97_t * ac97);
+int patch_vt1617a(ac97_t * ac97);
int patch_it2646(ac97_t * ac97);
int mpatch_si3036(ac97_t * ac97);
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index eb5c36d31a52..ce6c9fadb594 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -399,7 +399,7 @@ static int snd_ali_codec_ready( ali_t *codec,
unsigned long end_time;
unsigned int res;
- end_time = jiffies + 10 * (HZ >> 2);
+ end_time = jiffies + 10 * msecs_to_jiffies(250);
do {
res = snd_ali_5451_peek(codec,port);
if (! (res & 0x8000))
@@ -422,7 +422,7 @@ static int snd_ali_stimer_ready(ali_t *codec, int sched)
dwChk1 = snd_ali_5451_peek(codec, ALI_STIMER);
dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);
- end_time = jiffies + 10 * (HZ >> 2);
+ end_time = jiffies + 10 * msecs_to_jiffies(250);
do {
dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);
if (dwChk2 != dwChk1)
@@ -1842,7 +1842,7 @@ static int __devinit snd_ali_pcm(ali_t * codec, int device, struct ali_pcm_descr
return 0;
}
-struct ali_pcm_description ali_pcms[] = {
+static struct ali_pcm_description ali_pcms[] = {
{ "ALI 5451", ALI_CHANNELS, 1, &snd_ali_playback_ops, &snd_ali_capture_ops },
{ "ALI 5451 modem", 1, 1, &snd_ali_modem_playback_ops, &snd_ali_modem_capture_ops }
};
@@ -1959,9 +1959,9 @@ static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
static snd_kcontrol_new_t snd_ali5451_mixer_spdif[] __devinitdata = {
/* spdif aplayback switch */
/* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */
- ALI5451_SPDIF("IEC958 Output switch", 0, 0),
+ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0),
/* spdif out to spdif channel */
- ALI5451_SPDIF("IEC958 Channel Output Switch", 0, 1),
+ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1),
/* spdif in from spdif channel */
ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)
};
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index cafab4af5c57..188df085b7ee 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -248,6 +248,7 @@ struct snd_atiixp_dma {
unsigned int period_bytes, periods;
int opened;
int running;
+ int suspended;
int pcm_open_flag;
int ac97_pcm_type; /* index # of ac97_pcm to access, -1 = not used */
unsigned int saved_curptr;
@@ -699,12 +700,18 @@ static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
spin_lock(&chip->reg_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
dma->ops->enable_transfer(chip, 1);
dma->running = 1;
+ dma->suspended = 0;
break;
case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
dma->ops->enable_transfer(chip, 0);
dma->running = 0;
+ dma->suspended = cmd == SNDRV_PCM_TRIGGER_SUSPEND;
break;
default:
err = -EINVAL;
@@ -975,6 +982,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm_hw =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
@@ -1419,7 +1427,7 @@ static int snd_atiixp_suspend(snd_card_t *card, pm_message_t state)
snd_atiixp_aclink_down(chip);
snd_atiixp_chip_stop(chip);
- pci_set_power_state(chip->pci, 3);
+ pci_set_power_state(chip->pci, PCI_D3hot);
pci_disable_device(chip->pci);
return 0;
}
@@ -1430,7 +1438,7 @@ static int snd_atiixp_resume(snd_card_t *card)
int i;
pci_enable_device(chip->pci);
- pci_set_power_state(chip->pci, 0);
+ pci_set_power_state(chip->pci, PCI_D0);
pci_set_master(chip->pci);
snd_atiixp_aclink_reset(chip);
@@ -1443,7 +1451,7 @@ static int snd_atiixp_resume(snd_card_t *card)
for (i = 0; i < NUM_ATI_PCMDEVS; i++)
if (chip->pcmdevs[i]) {
atiixp_dma_t *dma = &chip->dmas[i];
- if (dma->substream && dma->running) {
+ if (dma->substream && dma->suspended) {
dma->ops->enable_dma(chip, 1);
writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN,
chip->remap_addr + dma->ops->llp_offset);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index a6b4b8d589fd..8d2002951bd7 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -265,6 +265,7 @@ struct snd_atiixp {
*/
static struct pci_device_id snd_atiixp_ids[] = {
{ 0x1002, 0x434d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
+ { 0x1002, 0x4378, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
{ 0, }
};
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 04dcefd8b8ff..38bd2b5dd434 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -33,7 +33,7 @@
/* hardware definition */
static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
.info =
- (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+ (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@@ -58,7 +58,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_adb = {
#ifndef CHIP_AU8820
static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
.info =
- (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+ (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@@ -78,7 +78,7 @@ static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = {
#endif
static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = {
.info =
- (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME |
+ (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID),
.formats =
@@ -220,8 +220,10 @@ snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream,
vortex_adb_allocroute(chip, -1,
params_channels(hw_params),
substream->stream, type);
- if (dma < 0)
+ if (dma < 0) {
+ spin_unlock_irq(&chip->lock);
return dma;
+ }
stream = substream->runtime->private_data = &chip->dma_adb[dma];
stream->substream = substream;
/* Setup Buffers. */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 95c289284267..7e27bfc37439 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -188,6 +188,14 @@ static ca0106_details_t ca0106_chip_details[] = {
.name = "MSI K8N Diamond MB [SB0438]",
.gpio_type = 1,
.i2c_adc = 1 } ,
+ /* Shuttle XPC SD31P which has an onboard Creative Labs Sound Blaster Live! 24-bit EAX
+ * high-definition 7.1 audio processor".
+ * Added using info from andrewvegan in alsa bug #1298
+ */
+ { .serial = 0x30381297,
+ .name = "Shuttle XPC SD31P [SD31P]",
+ .gpio_type = 1,
+ .i2c_adc = 1 } ,
{ .serial = 0,
.name = "AudigyLS [Unknown]" }
};
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 0e5e9ce0ff28..b6b8882ce704 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -297,7 +297,7 @@ static int snd_ca0106_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 4,
.info = snd_ca0106_spdif_info,
@@ -306,7 +306,7 @@ static snd_kcontrol_new_t snd_ca0106_spdif_mask_control =
static snd_kcontrol_new_t snd_ca0106_spdif_control =
{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 4,
.info = snd_ca0106_spdif_info,
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index b4503385ea69..b098b51099c2 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -306,7 +306,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
#define CM_REG_FM_PCI 0x50
/*
- * for CMI-8338 .. this is not valid for CMI-8738.
+ * access from SB-mixer port
*/
#define CM_REG_EXTENT_IND 0xf0
#define CM_VPHONE_MASK 0xe0 /* Phone volume control (0-3) << 5 */
@@ -315,6 +315,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address.");
#define CM_VSPKM 0x08 /* Speaker mute control, default high */
#define CM_RLOOPREN 0x04 /* Rec. R-channel enable */
#define CM_RLOOPLEN 0x02 /* Rec. L-channel enable */
+#define CM_VADMIC3 0x01 /* Mic record boost */
/*
* CMI-8338 spec ver 0.5 (this is not valid for CMI-8738):
@@ -488,32 +489,34 @@ struct snd_stru_cmipci {
/* read/write operations for dword register */
-inline static void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data)
+static inline void snd_cmipci_write(cmipci_t *cm, unsigned int cmd, unsigned int data)
{
outl(data, cm->iobase + cmd);
}
-inline static unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd)
+
+static inline unsigned int snd_cmipci_read(cmipci_t *cm, unsigned int cmd)
{
return inl(cm->iobase + cmd);
}
/* read/write operations for word register */
-inline static void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data)
+static inline void snd_cmipci_write_w(cmipci_t *cm, unsigned int cmd, unsigned short data)
{
outw(data, cm->iobase + cmd);
}
-inline static unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd)
+
+static inline unsigned short snd_cmipci_read_w(cmipci_t *cm, unsigned int cmd)
{
return inw(cm->iobase + cmd);
}
/* read/write operations for byte register */
-inline static void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data)
+static inline void snd_cmipci_write_b(cmipci_t *cm, unsigned int cmd, unsigned char data)
{
outb(data, cm->iobase + cmd);
}
-inline static unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd)
+static inline unsigned char snd_cmipci_read_b(cmipci_t *cm, unsigned int cmd)
{
return inb(cm->iobase + cmd);
}
@@ -1026,7 +1029,7 @@ static int snd_cmipci_spdif_mask_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_cmipci_spdif_mask __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_cmipci_spdif_mask_info,
.get = snd_cmipci_spdif_mask_get,
@@ -2133,8 +2136,12 @@ static snd_kcontrol_new_t snd_cmipci_mixers[] __devinitdata = {
CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
- CMIPCI_MIXER_SW_MONO("Mic Boost", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
+ CMIPCI_MIXER_SW_MONO("Mic Boost Playback Switch", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
+ CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
+ CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
+ CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+ CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
};
/*
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index eb3c52b03af3..c7a370d4f923 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -542,7 +542,7 @@ static void snd_cs4281_delay(unsigned int delay)
}
}
-inline static void snd_cs4281_delay_long(void)
+static inline void snd_cs4281_delay_long(void)
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index db212ecd792a..b9fff4ee6f9d 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -113,7 +113,7 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci,
return err;
}
#endif
- if ((err = snd_cs46xx_mixer(chip)) < 0) {
+ if ((err = snd_cs46xx_mixer(chip, 2)) < 0) {
snd_card_free(card);
return err;
}
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index fd4c50c88bc9..4b052158ee33 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -1243,8 +1243,8 @@ static snd_pcm_hardware_t snd_cs46xx_playback =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+ /*SNDRV_PCM_INFO_RESUME*/),
.formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@@ -1265,8 +1265,8 @@ static snd_pcm_hardware_t snd_cs46xx_capture =
{
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
+ /*SNDRV_PCM_INFO_RESUME*/),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 5500,
@@ -2231,7 +2231,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Output Switch",
+ .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
@@ -2239,7 +2239,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Input Switch",
+ .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,SWITCH),
.info = snd_mixer_boolean_info,
.get = snd_cs46xx_iec958_get,
.put = snd_cs46xx_iec958_put,
@@ -2249,7 +2249,7 @@ static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
/* Input IEC958 volume does not work for the moment. (Benny) */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Input Volume",
+ .name = SNDRV_CTL_NAME_IEC958("Input ",NONE,VOLUME),
.info = snd_cs46xx_vol_info,
.get = snd_cs46xx_vol_iec958_get,
.put = snd_cs46xx_vol_iec958_put,
@@ -2400,8 +2400,7 @@ static void snd_cs46xx_codec_reset (ac97_t * ac97)
if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
return;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/100);
+ msleep(10);
} while (time_after_eq(end_time, jiffies));
snd_printk("CS46xx secondary codec dont respond!\n");
@@ -2435,14 +2434,13 @@ static int __devinit cs46xx_detect_codec(cs46xx_t *chip, int codec)
err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[codec]);
return err;
}
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/100);
+ msleep(10);
}
snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec);
return -ENXIO;
}
-int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
+int __devinit snd_cs46xx_mixer(cs46xx_t *chip, int spdif_device)
{
snd_card_t *card = chip->card;
snd_ctl_elem_id_t id;
@@ -2478,6 +2476,8 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
for (idx = 0; idx < ARRAY_SIZE(snd_cs46xx_controls); idx++) {
snd_kcontrol_t *kctl;
kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip);
+ if (kctl && kctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM)
+ kctl->id.device = spdif_device;
if ((err = snd_ctl_add(card, kctl)) < 0)
return err;
}
@@ -3018,8 +3018,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip)
/*
* Wait until the PLL has stabilized.
*/
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/10); /* 100ms */
+ msleep(100);
/*
* Turn on clocking of the core so that we can setup the serial ports.
@@ -3072,8 +3071,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip)
*/
if (snd_cs46xx_peekBA0(chip, BA0_ACSTS) & ACSTS_CRDY)
goto ok1;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ+99)/100);
+ msleep(10);
}
@@ -3122,8 +3120,7 @@ static int snd_cs46xx_chip_init(cs46xx_t *chip)
*/
if ((snd_cs46xx_peekBA0(chip, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
goto ok2;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ+99)/100);
+ msleep(10);
}
#ifndef CONFIG_SND_CS46XX_NEW_DSP
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 2085a998eaeb..fc377c4b666c 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -52,6 +52,7 @@ static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static uint subsystem[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* Force card subsystem model */
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
@@ -71,7 +72,8 @@ module_param_array(max_buffer_size, int, NULL, 0444);
MODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB.");
module_param_array(enable_ir, bool, NULL, 0444);
MODULE_PARM_DESC(enable_ir, "Enable IR.");
-
+module_param_array(subsystem, uint, NULL, 0444);
+MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
/*
* Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
*/
@@ -122,7 +124,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
max_buffer_size[dev] = 1024;
if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
(long)max_buffer_size[dev] * 1024 * 1024,
- enable_ir[dev],
+ enable_ir[dev], subsystem[dev],
&emu)) < 0) {
snd_card_free(card);
return err;
@@ -140,14 +142,14 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
return err;
}
/* This stores the periods table. */
- if (emu->audigy && emu->revision == 4) { /* P16V */
+ if (emu->card_capabilities->ca0151_chip) { /* P16V */
if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) {
snd_p16v_free(emu);
return -ENOMEM;
}
}
- if ((err = snd_emu10k1_mixer(emu)) < 0) {
+ if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0) {
snd_card_free(card);
return err;
}
@@ -161,7 +163,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
snd_card_free(card);
return err;
}
- if (emu->audigy && emu->revision == 4) { /* P16V */
+ if (emu->card_capabilities->ca0151_chip) { /* P16V */
if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) {
snd_card_free(card);
return err;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index a341e758acde..e69d5b739e80 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -191,7 +191,7 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
/* Set playback routing. */
snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4);
}
- if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
+ if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
/* Hacks for Alice3 to work independent of haP16V driver */
u32 tmp;
@@ -253,6 +253,8 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
else
outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
+ /* FIXME: Remove all these emu->model and replace it with a card recognition parameter,
+ * e.g. card_capabilities->joystick */
} else if (emu->model == 0x20 ||
emu->model == 0xc400 ||
(emu->model == 0x21 && emu->revision < 6))
@@ -299,12 +301,12 @@ static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir)
if (emu->audigy) {
outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
- if (emu->revision == 4) { /* audigy2 */
+ if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
/* Unmute Analog now. Set GPO6 to 1 for Apollo.
* This has to be done after init ALice3 I2SOut beyond 48KHz.
* So, sequence is important. */
outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
- } else if (emu->serial == 0x10011102) { /* audigy2 value */
+ } else if (emu->card_capabilities->ca0108_chip) { /* audigy2 value */
/* Unmute Analog now. */
outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);
} else {
@@ -614,6 +616,7 @@ static int snd_emu10k1_dev_free(snd_device_t *device)
static emu_chip_details_t emu_chip_details[] = {
/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
+ /* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
.driver = "Audigy2", .name = "Audigy 2 Value [SB0400]",
.id = "Audigy2",
@@ -627,6 +630,14 @@ static emu_chip_details_t emu_chip_details[] = {
.emu10k2_chip = 1,
.ca0108_chip = 1,
.ac97_chip = 1} ,
+ /* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
+ .driver = "Audigy2", .name = "E-mu 1212m [4001]",
+ .id = "EMU1212m",
+ .emu10k2_chip = 1,
+ .ca0102_chip = 1,
+ .ecard = 1} ,
+ /* Tested by James@superbug.co.uk 3rd July 2005 */
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
.driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]",
.id = "Audigy2",
@@ -687,18 +698,18 @@ static emu_chip_details_t emu_chip_details[] = {
.ca0151_chip = 1,
.spdif_bug = 1,
.ac97_chip = 1} ,
- {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052,
- .driver = "Audigy", .name = "Audigy 1 ES [SB0160]",
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
+ .driver = "Audigy", .name = "Audigy 1 [SB0090]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
- .spdif_bug = 1,
.ac97_chip = 1} ,
- {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
- .driver = "Audigy", .name = "Audigy 1 [SB0090]",
+ {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102,
+ .driver = "Audigy", .name = "Audigy 1 ES [SB0160]",
.id = "Audigy",
.emu10k2_chip = 1,
.ca0102_chip = 1,
+ .spdif_bug = 1,
.ac97_chip = 1} ,
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
.driver = "Audigy", .name = "Audigy 1 [SB0090]",
@@ -712,54 +723,57 @@ static emu_chip_details_t emu_chip_details[] = {
.emu10k2_chip = 1,
.ca0102_chip = 1,
.ac97_chip = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
- .driver = "EMU10K1", .name = "E-mu APS [4001]",
- .id = "APS",
- .emu10k1_chip = 1,
- .ecard = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
- .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
+ .driver = "EMU10K1", .name = "SBLive! [SB0105]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
- .driver = "EMU10K1", .name = "SB Live 5.1",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102,
+ .driver = "EMU10K1", .name = "SBLive! Value [SB0103]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
- .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
+ .driver = "EMU10K1", .name = "SBLive! Value [SB0101]",
.id = "Live",
.emu10k1_chip = 1,
- .ac97_chip = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
- .driver = "EMU10K1", .name = "SBLive! [CT4620]",
+ .ac97_chip = 1,
+ .sblive51 = 1} ,
+ /* Tested by Thomas Zehetbauer 27th Aug 2005 */
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
+ .driver = "EMU10K1", .name = "SB Live 5.1 [SB0220]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4670]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
+ .driver = "EMU10K1", .name = "SB Live 5.1",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4780]",
+ /* Tested by alsa bugtrack user "hus" 12th Sept 2005 */
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
+ .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
- .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4850]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4830]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
+ .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]",
+ .id = "Live",
+ .emu10k1_chip = 1,
+ .ac97_chip = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4871]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
@@ -770,50 +784,50 @@ static emu_chip_details_t emu_chip_details[] = {
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4832]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4870]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4850]",
+ /* Tested by James@superbug.co.uk 3rd July 2005 */
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4832]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4870]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4830]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
- .driver = "EMU10K1", .name = "SBLive! Value [CT4871]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
+ .driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
- .driver = "EMU10K1", .name = "SBLive! Value [SB0060]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4780]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
- .driver = "EMU10K1", .name = "SBLive! Value [SB0101]",
- .id = "Live",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
+ .driver = "EMU10K1", .name = "E-mu APS [4001]",
+ .id = "APS",
.emu10k1_chip = 1,
- .ac97_chip = 1,
- .sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806A1102,
- .driver = "EMU10K1", .name = "SBLive! Value [SB0103]",
+ .ecard = 1} ,
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
+ .driver = "EMU10K1", .name = "SBLive! [CT4620]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
.sblive51 = 1} ,
- {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
- .driver = "EMU10K1", .name = "SBLive! [SB0105]",
+ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
+ .driver = "EMU10K1", .name = "SBLive! Value [CT4670]",
.id = "Live",
.emu10k1_chip = 1,
.ac97_chip = 1,
@@ -833,6 +847,7 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
unsigned short extout_mask,
long max_cache_bytes,
int enable_ir,
+ uint subsystem,
emu10k1_t ** remu)
{
emu10k1_t *emu;
@@ -878,10 +893,16 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
for (c = emu_chip_details; c->vendor; c++) {
if (c->vendor == pci->vendor && c->device == pci->device) {
- if (c->subsystem && c->subsystem != emu->serial)
- continue;
- if (c->revision && c->revision != emu->revision)
- continue;
+ if (subsystem) {
+ if (c->subsystem && (c->subsystem == subsystem) ) {
+ break;
+ } else continue;
+ } else {
+ if (c->subsystem && (c->subsystem != emu->serial) )
+ continue;
+ if (c->revision && c->revision != emu->revision)
+ continue;
+ }
break;
}
}
@@ -892,10 +913,14 @@ int __devinit snd_emu10k1_create(snd_card_t * card,
return -ENOENT;
}
emu->card_capabilities = c;
- if (c->subsystem != 0)
+ if (c->subsystem && !subsystem)
snd_printdd("Sound card name=%s\n", c->name);
- else
- snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial);
+ else if (subsystem)
+ snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n",
+ c->name, pci->vendor, pci->device, emu->serial, c->subsystem);
+ else
+ snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n",
+ c->name, pci->vendor, pci->device, emu->serial);
if (!*card->id && c->id) {
int i, n = 0;
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index e90c5ddd1d17..52c7826df440 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1183,7 +1183,7 @@ static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 3,
.info = snd_emu10k1x_spdif_info,
@@ -1192,7 +1192,7 @@ static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control =
static snd_kcontrol_new_t snd_emu10k1x_spdif_control =
{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 3,
.info = snd_emu10k1x_spdif_info,
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 0529fb281125..637c555cfdb1 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1159,12 +1159,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
/* Optical SPDIF Playback Volume */
A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L);
A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* Optical SPDIF Capture Volume */
A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L);
A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R);
- snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0);
+ snd_emu10k1_init_stereo_control(&controls[nctl++], SNDRV_CTL_NAME_IEC958("Optical ",CAPTURE,VOLUME), gpr, 0);
gpr += 2;
/* Line2 Playback Volume */
@@ -1389,7 +1389,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000);
}
}
- snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+ snd_emu10k1_init_stereo_onoff_control(controls + nctl++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
gpr += 2;
A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS);
@@ -1716,7 +1716,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 TTL Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z);
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Playback Volume", gpr, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 TTL Capture Volume + Switch */
@@ -1724,8 +1724,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Capture Volume", gpr, 0);
- snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 TTL Capture Switch", gpr + 2, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,VOLUME), gpr, 0);
+ snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("TTL ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@@ -1750,7 +1750,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 Optical Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z);
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 Optical Capture Volume */
@@ -1758,8 +1758,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0);
- snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,VOLUME), gpr, 0);
+ snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("LiveDrive ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@@ -1784,7 +1784,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
/* IEC958 Coax Playback Volume */
for (z = 0; z < 2; z++)
VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z);
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Playback Volume", gpr, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",PLAYBACK,VOLUME), gpr, 0);
gpr += 2;
/* IEC958 Coax Capture Volume + Switch */
@@ -1792,8 +1792,8 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z);
VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z);
}
- snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Capture Volume", gpr, 0);
- snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Coaxial Capture Switch", gpr + 2, 0);
+ snd_emu10k1_init_stereo_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,VOLUME), gpr, 0);
+ snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Coaxial ",CAPTURE,SWITCH), gpr + 2, 0);
gpr += 4;
}
@@ -1920,7 +1920,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu)
#endif
}
- snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Raw Playback Switch", gpr, 0);
+ snd_emu10k1_init_stereo_onoff_control(controls + i++, SNDRV_CTL_NAME_IEC958("Optical Raw ",PLAYBACK,SWITCH), gpr, 0);
gpr += 2;
}
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 6be82c5fe138..d71a72e84bcc 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -181,7 +181,7 @@ static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
.count = 4,
.info = snd_emu10k1_spdif_info,
@@ -190,7 +190,7 @@ static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
static snd_kcontrol_new_t snd_emu10k1_spdif_control =
{
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
.count = 4,
.info = snd_emu10k1_spdif_info,
@@ -295,7 +295,7 @@ static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Send Routing",
.count = 32,
.info = snd_emu10k1_send_routing_info,
@@ -364,7 +364,7 @@ static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Send Volume",
.count = 32,
.info = snd_emu10k1_send_volume_info,
@@ -427,7 +427,7 @@ static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_emu10k1_attn_control =
{
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "EMU10K1 PCM Volume",
.count = 32,
.info = snd_emu10k1_attn_info,
@@ -737,7 +737,8 @@ static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
return -ENOENT;
}
-int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
+int __devinit snd_emu10k1_mixer(emu10k1_t *emu,
+ int pcm_device, int multi_device)
{
int err, pcm;
snd_kcontrol_t *kctl;
@@ -852,29 +853,35 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = pcm_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
return -ENOMEM;
+ kctl->id.device = multi_device;
if ((err = snd_ctl_add(card, kctl)))
return err;
@@ -924,10 +931,14 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
/* sb live! and audigy */
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
return -ENOMEM;
+ if (!emu->audigy)
+ kctl->id.device = emu->pcm_efx->device;
if ((err = snd_ctl_add(card, kctl)))
return err;
if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
return -ENOMEM;
+ if (!emu->audigy)
+ kctl->id.device = emu->pcm_efx->device;
if ((err = snd_ctl_add(card, kctl)))
return err;
}
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 520b99af5f55..9c35f6dde1b5 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1682,6 +1682,7 @@ static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm)
int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
+ snd_kcontrol_t *kctl;
int err;
if (rpcm)
@@ -1714,7 +1715,11 @@ int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm
emu->efx_voices_mask[0] = 0xffff0000;
emu->efx_voices_mask[1] = 0;
}
- snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu));
+ kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.device = device;
+ snd_ctl_add(emu->card, kctl);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024);
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 7a595f0dd7a1..6afeaeab3e13 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -495,7 +495,7 @@ static int synth_free_pages(emu10k1_t *emu, emu10k1_memblk_t *blk)
}
/* calculate buffer pointer from offset address */
-inline static void *offset_ptr(emu10k1_t *emu, int page, int offset)
+static inline void *offset_ptr(emu10k1_t *emu, int page, int offset)
{
char *ptr;
snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL);
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 98f980189892..a1691330d3b6 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -822,7 +822,7 @@ static int snd_p16v_volume_put_analog_unknown(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_p16v_volume_control_analog_front =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Analog Front Volume",
+ .name = "HD Analog Front Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_analog_front,
.put = snd_p16v_volume_put_analog_front
@@ -831,7 +831,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_analog_front =
static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Analog Center/LFE Volume",
+ .name = "HD Analog Center/LFE Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_analog_center_lfe,
.put = snd_p16v_volume_put_analog_center_lfe
@@ -840,7 +840,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe =
static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Analog Unknown Volume",
+ .name = "HD Analog Unknown Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_analog_unknown,
.put = snd_p16v_volume_put_analog_unknown
@@ -849,7 +849,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown =
static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Analog Rear Volume",
+ .name = "HD Analog Rear Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_analog_rear,
.put = snd_p16v_volume_put_analog_rear
@@ -858,7 +858,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear =
static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD SPDIF Front Volume",
+ .name = "HD SPDIF Front Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_spdif_front,
.put = snd_p16v_volume_put_spdif_front
@@ -867,7 +867,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front =
static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD SPDIF Center/LFE Volume",
+ .name = "HD SPDIF Center/LFE Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_spdif_center_lfe,
.put = snd_p16v_volume_put_spdif_center_lfe
@@ -876,7 +876,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe =
static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD SPDIF Unknown Volume",
+ .name = "HD SPDIF Unknown Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_spdif_unknown,
.put = snd_p16v_volume_put_spdif_unknown
@@ -885,7 +885,7 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown =
static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD SPDIF Rear Volume",
+ .name = "HD SPDIF Rear Playback Volume",
.info = snd_p16v_volume_info,
.get = snd_p16v_volume_get_spdif_rear,
.put = snd_p16v_volume_put_spdif_rear
@@ -936,7 +936,7 @@ static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Capture source",
+ .name = "HD source Capture",
.info = snd_p16v_capture_source_info,
.get = snd_p16v_capture_source_get,
.put = snd_p16v_capture_source_put
@@ -985,7 +985,7 @@ static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata =
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "HD Capture channel",
+ .name = "HD channel Capture",
.info = snd_p16v_capture_channel_info,
.get = snd_p16v_capture_channel_get,
.put = snd_p16v_capture_channel_put
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 4e63498a58b2..f06b95f41a1d 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -685,6 +685,15 @@ static unsigned short snd_es1371_codec_read(ac97_t *ac97,
return 0;
}
+static void snd_es1371_codec_wait(ac97_t *ac97)
+{
+ msleep(750);
+ snd_es1371_codec_read(ac97, AC97_RESET);
+ snd_es1371_codec_read(ac97, AC97_VENDOR_ID1);
+ snd_es1371_codec_read(ac97, AC97_VENDOR_ID2);
+ msleep(50);
+}
+
static void snd_es1371_adc_rate(ensoniq_t * ensoniq, unsigned int rate)
{
unsigned int n, truncm, freq, result;
@@ -1435,7 +1444,7 @@ static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
/* spdif controls */
static snd_kcontrol_new_t snd_es1371_mixer_spdif[] __devinitdata = {
- ES1371_SPDIF("IEC958 Playback Switch"),
+ ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)),
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
@@ -1585,6 +1594,7 @@ static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq)
static ac97_bus_ops_t ops = {
.write = snd_es1371_codec_write,
.read = snd_es1371_codec_read,
+ .wait = snd_es1371_codec_wait,
};
if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0)
@@ -2008,21 +2018,11 @@ static int __devinit snd_ensoniq_create(snd_card_t * card,
if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
pci->device == es1371_ac97_reset_hack[idx].did &&
ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
- unsigned long tmo;
- signed long tmo2;
-
ensoniq->cssr |= ES_1371_ST_AC97_RST;
outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
/* need to delay around 20ms(bleech) to give
some CODECs enough time to wakeup */
- tmo = jiffies + (HZ / 50) + 1;
- while (1) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(tmo2);
- }
+ msleep(20);
break;
}
/* AC'97 warm reset to start the bitclk */
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index ea889b311390..9d7a28783930 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -636,7 +636,7 @@ static void __maestro_write(es1968_t *chip, u16 reg, u16 data)
chip->maestro_map[reg] = data;
}
-inline static void maestro_write(es1968_t *chip, u16 reg, u16 data)
+static inline void maestro_write(es1968_t *chip, u16 reg, u16 data)
{
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -654,7 +654,7 @@ static u16 __maestro_read(es1968_t *chip, u16 reg)
return chip->maestro_map[reg];
}
-inline static u16 maestro_read(es1968_t *chip, u16 reg)
+static inline u16 maestro_read(es1968_t *chip, u16 reg)
{
unsigned long flags;
u16 result;
@@ -664,11 +664,6 @@ inline static u16 maestro_read(es1968_t *chip, u16 reg)
return result;
}
-#define big_mdelay(msec) do {\
- set_current_state(TASK_UNINTERRUPTIBLE);\
- schedule_timeout(((msec) * HZ + 999) / 1000);\
-} while (0)
-
/* Wait for the codec bus to be free */
static int snd_es1968_ac97_wait(es1968_t *chip)
{
@@ -755,7 +750,7 @@ static void __apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data)
apu_data_set(chip, data);
}
-inline static void apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data)
+static inline void apu_set_register(es1968_t *chip, u16 channel, u8 reg, u16 data)
{
unsigned long flags;
spin_lock_irqsave(&chip->reg_lock, flags);
@@ -771,7 +766,7 @@ static u16 __apu_get_register(es1968_t *chip, u16 channel, u8 reg)
return __maestro_read(chip, IDR0_DATA_PORT);
}
-inline static u16 apu_get_register(es1968_t *chip, u16 channel, u8 reg)
+static inline u16 apu_get_register(es1968_t *chip, u16 channel, u8 reg)
{
unsigned long flags;
u16 v;
@@ -957,7 +952,7 @@ static u32 snd_es1968_compute_rate(es1968_t *chip, u32 freq)
}
/* get current pointer */
-inline static unsigned int
+static inline unsigned int
snd_es1968_get_dma_ptr(es1968_t *chip, esschan_t *es)
{
unsigned int offset;
@@ -978,7 +973,7 @@ static void snd_es1968_apu_set_freq(es1968_t *chip, int apu, int freq)
}
/* spin lock held */
-inline static void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode)
+static inline void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode)
{
/* set the APU mode */
__apu_set_register(esm, apu, 0,
@@ -1809,8 +1804,7 @@ static void __devinit es1968_measure_clock(es1968_t *chip)
snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
do_gettimeofday(&start_time);
spin_unlock_irq(&chip->reg_lock);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20); /* 50 msec */
+ msleep(50);
spin_lock_irq(&chip->reg_lock);
offset = __apu_get_register(chip, apu, 5);
do_gettimeofday(&stop_time);
@@ -2093,7 +2087,7 @@ static void snd_es1968_ac97_reset(es1968_t *chip)
outw(0x0000, ioaddr + 0x60); /* write 0 to gpio 0 */
udelay(20);
outw(0x0001, ioaddr + 0x60); /* write 1 to gpio 1 */
- big_mdelay(20);
+ msleep(20);
outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */
outw((inw(ioaddr + 0x38) & 0xfffc) | 0x1, ioaddr + 0x38);
@@ -2109,7 +2103,7 @@ static void snd_es1968_ac97_reset(es1968_t *chip)
outw(0x0001, ioaddr + 0x60); /* write 1 to gpio */
udelay(20);
outw(0x0009, ioaddr + 0x60); /* write 9 to gpio */
- big_mdelay(500);
+ msleep(500);
//outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
@@ -2135,7 +2129,7 @@ static void snd_es1968_ac97_reset(es1968_t *chip)
if (w > 10000) {
outb(inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */
- big_mdelay(500); /* oh my.. */
+ msleep(500); /* oh my.. */
outb(inb(ioaddr + 0x37) & ~0x08,
ioaddr + 0x37);
udelay(1);
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index ff10e637a95e..36b2f62e8573 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1155,10 +1155,10 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1),
static snd_kcontrol_new_t snd_fm801_controls_multi[] __devinitdata = {
FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0),
FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0),
-FM801_SINGLE("IEC958 Capture Switch", FM801_I2S_MODE, 8, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Playback Switch", FM801_I2S_MODE, 9, 1, 0),
-FM801_SINGLE("IEC958 Raw Data Capture Switch", FM801_I2S_MODE, 10, 1, 0),
-FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",PLAYBACK,SWITCH), FM801_I2S_MODE, 9, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("Raw Data ",CAPTURE,SWITCH), FM801_I2S_MODE, 10, 1, 0),
+FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), FM801_GEN_CTRL, 2, 1, 0),
};
static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus)
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index bd8cb33c4fb4..ddfb5ff7fb8f 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,5 +1,5 @@
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o
+snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o
ifdef CONFIG_PROC_FS
snd-hda-codec-objs += hda_proc.o
endif
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e2cf02387289..20f7762f7144 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -432,22 +432,26 @@ void snd_hda_get_codec_name(struct hda_codec *codec,
}
/*
- * look for an AFG node
- *
- * return 0 if not found
+ * look for an AFG and MFG nodes
*/
-static int look_for_afg_node(struct hda_codec *codec)
+static void setup_fg_nodes(struct hda_codec *codec)
{
int i, total_nodes;
hda_nid_t nid;
total_nodes = snd_hda_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
for (i = 0; i < total_nodes; i++, nid++) {
- if ((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff) ==
- AC_GRP_AUDIO_FUNCTION)
- return nid;
+ switch((snd_hda_param_read(codec, nid, AC_PAR_FUNCTION_TYPE) & 0xff)) {
+ case AC_GRP_AUDIO_FUNCTION:
+ codec->afg = nid;
+ break;
+ case AC_GRP_MODEM_FUNCTION:
+ codec->mfg = nid;
+ break;
+ default:
+ break;
+ }
}
- return 0;
}
/*
@@ -507,10 +511,9 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr,
codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
- /* FIXME: support for multiple AFGs? */
- codec->afg = look_for_afg_node(codec);
- if (! codec->afg) {
- snd_printdd("hda_codec: no AFG node found\n");
+ setup_fg_nodes(codec);
+ if (! codec->afg && ! codec->mfg) {
+ snd_printdd("hda_codec: no AFG or MFG node found\n");
snd_hda_codec_free(codec);
return -ENODEV;
}
@@ -749,12 +752,14 @@ int snd_hda_mixer_amp_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
long *valp = ucontrol->value.integer.value;
int change = 0;
- if (chs & 1)
+ if (chs & 1) {
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
0x7f, *valp);
+ valp++;
+ }
if (chs & 2)
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
- 0x7f, valp[1]);
+ 0x7f, *valp);
return change;
}
@@ -796,12 +801,15 @@ int snd_hda_mixer_amp_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
long *valp = ucontrol->value.integer.value;
int change = 0;
- if (chs & 1)
+ if (chs & 1) {
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
0x80, *valp ? 0 : 0x80);
+ valp++;
+ }
if (chs & 2)
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
- 0x80, valp[1] ? 0 : 0x80);
+ 0x80, *valp ? 0 : 0x80);
+
return change;
}
@@ -1155,8 +1163,16 @@ int snd_hda_build_controls(struct hda_bus *bus)
/*
* stream formats
*/
-static unsigned int rate_bits[][3] = {
+struct hda_rate_tbl {
+ unsigned int hz;
+ unsigned int alsa_bits;
+ unsigned int hda_fmt;
+};
+
+static struct hda_rate_tbl rate_bits[] = {
/* rate in Hz, ALSA rate bitmask, HDA format value */
+
+ /* autodetected value used in snd_hda_query_supported_pcm */
{ 8000, SNDRV_PCM_RATE_8000, 0x0500 }, /* 1/6 x 48 */
{ 11025, SNDRV_PCM_RATE_11025, 0x4300 }, /* 1/4 x 44 */
{ 16000, SNDRV_PCM_RATE_16000, 0x0200 }, /* 1/3 x 48 */
@@ -1168,7 +1184,11 @@ static unsigned int rate_bits[][3] = {
{ 96000, SNDRV_PCM_RATE_96000, 0x0800 }, /* 2 x 48 */
{ 176400, SNDRV_PCM_RATE_176400, 0x5800 },/* 4 x 44 */
{ 192000, SNDRV_PCM_RATE_192000, 0x1800 }, /* 4 x 48 */
- { 0 }
+
+ /* not autodetected value */
+ { 9600, SNDRV_PCM_RATE_KNOT, 0x0400 }, /* 1/5 x 48 */
+
+ { 0 } /* terminator */
};
/**
@@ -1190,12 +1210,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
int i;
unsigned int val = 0;
- for (i = 0; rate_bits[i][0]; i++)
- if (rate_bits[i][0] == rate) {
- val = rate_bits[i][2];
+ for (i = 0; rate_bits[i].hz; i++)
+ if (rate_bits[i].hz == rate) {
+ val = rate_bits[i].hda_fmt;
break;
}
- if (! rate_bits[i][0]) {
+ if (! rate_bits[i].hz) {
snd_printdd("invalid rate %d\n", rate);
return 0;
}
@@ -1258,9 +1278,9 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
if (ratesp) {
u32 rates = 0;
- for (i = 0; rate_bits[i][0]; i++) {
+ for (i = 0; rate_bits[i].hz; i++) {
if (val & (1 << i))
- rates |= rate_bits[i][1];
+ rates |= rate_bits[i].alsa_bits;
}
*ratesp = rates;
}
@@ -1352,13 +1372,13 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
}
rate = format & 0xff00;
- for (i = 0; rate_bits[i][0]; i++)
- if (rate_bits[i][2] == rate) {
+ for (i = 0; rate_bits[i].hz; i++)
+ if (rate_bits[i].hda_fmt == rate) {
if (val & (1 << i))
break;
return 0;
}
- if (! rate_bits[i][0])
+ if (! rate_bits[i].hz)
return 0;
stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
@@ -1541,8 +1561,11 @@ int snd_hda_check_board_config(struct hda_codec *codec, const struct hda_board_c
for (c = tbl; c->modelname || c->pci_subvendor; c++) {
if (c->pci_subvendor == subsystem_vendor &&
(! c->pci_subdevice /* all match */||
- (c->pci_subdevice == subsystem_device)))
+ (c->pci_subdevice == subsystem_device))) {
+ snd_printdd(KERN_INFO "hda_codec: PCI %x:%x, codec config %d is selected\n",
+ subsystem_vendor, subsystem_device, c->config);
return c->config;
+ }
}
}
return -1;
@@ -1803,11 +1826,25 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *c
cfg->line_out_pins[j] = nid;
}
- /* Swap surround and CLFE: the association order is front/CLFE/surr/back */
- if (cfg->line_outs >= 3) {
+ /* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ * 4-ch: front/surr => OK as it is
+ * 6-ch: front/clfe/surr
+ * 8-ch: front/clfe/side/surr
+ */
+ switch (cfg->line_outs) {
+ case 3:
nid = cfg->line_out_pins[1];
cfg->line_out_pins[1] = cfg->line_out_pins[2];
cfg->line_out_pins[2] = nid;
+ break;
+ case 4:
+ nid = cfg->line_out_pins[1];
+ cfg->line_out_pins[1] = cfg->line_out_pins[3];
+ cfg->line_out_pins[3] = cfg->line_out_pins[2];
+ cfg->line_out_pins[2] = nid;
+ break;
}
return 0;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 59991560d492..63a29a8a2860 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -262,6 +262,9 @@ enum {
#define AC_PINCTL_OUT_EN (1<<6)
#define AC_PINCTL_HP_EN (1<<7)
+/* Unsolicited response - 8bit */
+#define AC_USRSP_EN (1<<7)
+
/* configuration default - 32bit */
#define AC_DEFCFG_SEQUENCE (0xf<<0)
#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
@@ -511,6 +514,7 @@ struct hda_codec {
struct list_head list; /* list point */
hda_nid_t afg; /* AFG node id */
+ hda_nid_t mfg; /* MFG node id */
/* ids */
u32 vendor_id;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 2d046abb5911..1229227af5b5 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -881,6 +881,11 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec)
struct hda_gspec *spec;
int err;
+ if(!codec->afg) {
+ snd_printdd("hda_generic: no generic modem yet\n");
+ return -ENODEV;
+ }
+
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL) {
printk(KERN_ERR "hda_generic: can't allocate spec\n");
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 5e0cca36ed57..15107df1f490 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -71,7 +71,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ESB2},"
"{ATI, SB450},"
"{VIA, VT8251},"
- "{VIA, VT8237A}}");
+ "{VIA, VT8237A},"
+ "{SiS, SIS966},"
+ "{ULI, M5461}}");
MODULE_DESCRIPTION("Intel HDA driver");
#define SFX "hda-intel: "
@@ -141,9 +143,24 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
*/
/* max number of SDs */
-#define MAX_ICH6_DEV 8
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_CAPTURE_INDEX 0
+#define ICH6_NUM_CAPTURE 4
+#define ICH6_PLAYBACK_INDEX 4
+#define ICH6_NUM_PLAYBACK 4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_CAPTURE_INDEX 0
+#define ULI_NUM_CAPTURE 5
+#define ULI_PLAYBACK_INDEX 5
+#define ULI_NUM_PLAYBACK 6
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV 16
+
/* max number of fragments - we may use more if allocating more pages for BDL */
-#define AZX_MAX_FRAG (PAGE_SIZE / (MAX_ICH6_DEV * 16))
+#define BDL_SIZE PAGE_ALIGN(8192)
+#define AZX_MAX_FRAG (BDL_SIZE / (MAX_AZX_DEV * 16))
/* max buffer size - no h/w limit, you can increase as you like */
#define AZX_MAX_BUF_SIZE (1024*1024*1024)
/* max number of PCM devics per card */
@@ -178,6 +195,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
+/* GCTL unsolicited response enable bit */
+#define ICH6_GCTL_UREN (1<<8)
+
/* GCTL reset bit */
#define ICH6_GCTL_RESET (1<<0)
@@ -197,7 +217,6 @@ enum {
};
/* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_PCI_DEVICE_ID 0x437b
#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42
#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02
@@ -255,6 +274,14 @@ struct snd_azx {
snd_card_t *card;
struct pci_dev *pci;
+ /* chip type specific */
+ int driver_type;
+ int playback_streams;
+ int playback_index_offset;
+ int capture_streams;
+ int capture_index_offset;
+ int num_streams;
+
/* pci resources */
unsigned long addr;
void __iomem *remap_addr;
@@ -264,8 +291,8 @@ struct snd_azx {
spinlock_t reg_lock;
struct semaphore open_mutex;
- /* streams */
- azx_dev_t azx_dev[MAX_ICH6_DEV];
+ /* streams (x num_streams) */
+ azx_dev_t *azx_dev;
/* PCM */
unsigned int pcm_devs;
@@ -289,6 +316,23 @@ struct snd_azx {
unsigned int initialized: 1;
};
+/* driver types */
+enum {
+ AZX_DRIVER_ICH,
+ AZX_DRIVER_ATI,
+ AZX_DRIVER_VIA,
+ AZX_DRIVER_SIS,
+ AZX_DRIVER_ULI,
+};
+
+static char *driver_short_names[] __devinitdata = {
+ [AZX_DRIVER_ICH] = "HDA Intel",
+ [AZX_DRIVER_ATI] = "HDA ATI SB",
+ [AZX_DRIVER_VIA] = "HDA VIA VT82xx",
+ [AZX_DRIVER_SIS] = "HDA SIS966",
+ [AZX_DRIVER_ULI] = "HDA ULI M5461"
+};
+
/*
* macros for easy use
*/
@@ -357,6 +401,8 @@ static void azx_init_cmd_io(azx_t *chip)
azx_writel(chip, CORBLBASE, (u32)chip->corb.addr);
azx_writel(chip, CORBUBASE, upper_32bit(chip->corb.addr));
+ /* set the corb size to 256 entries (ULI requires explicitly) */
+ azx_writeb(chip, CORBSIZE, 0x02);
/* set the corb write pointer to 0 */
azx_writew(chip, CORBWP, 0);
/* reset the corb hw read pointer */
@@ -370,6 +416,8 @@ static void azx_init_cmd_io(azx_t *chip)
azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr);
azx_writel(chip, RIRBUBASE, upper_32bit(chip->rirb.addr));
+ /* set the rirb size to 256 entries (ULI requires explicitly) */
+ azx_writeb(chip, RIRBSIZE, 0x02);
/* reset the rirb hw write pointer */
azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR);
/* set N=1, get RIRB response interrupt for new entry */
@@ -562,6 +610,9 @@ static int azx_reset(azx_t *chip)
return -EBUSY;
}
+ /* Accept unsolicited responses */
+ azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+
/* detect codecs */
if (! chip->codec_mask) {
chip->codec_mask = azx_readw(chip, STATESTS);
@@ -590,7 +641,7 @@ static void azx_int_disable(azx_t *chip)
int i;
/* disable interrupts in stream descriptor */
- for (i = 0; i < MAX_ICH6_DEV; i++) {
+ for (i = 0; i < chip->num_streams; i++) {
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_sd_writeb(azx_dev, SD_CTL,
azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK);
@@ -610,7 +661,7 @@ static void azx_int_clear(azx_t *chip)
int i;
/* clear stream status */
- for (i = 0; i < MAX_ICH6_DEV; i++) {
+ for (i = 0; i < chip->num_streams; i++) {
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
}
@@ -680,8 +731,7 @@ static void azx_init_chip(azx_t *chip)
}
/* For ATI SB450 azalia HD audio, we need to enable snoop */
- if (chip->pci->vendor == PCI_VENDOR_ID_ATI &&
- chip->pci->device == ATI_SB450_HDAUDIO_PCI_DEVICE_ID) {
+ if (chip->driver_type == AZX_DRIVER_ATI) {
pci_read_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
&ati_misc_cntl2);
pci_write_config_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR,
@@ -708,7 +758,7 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs)
return IRQ_NONE;
}
- for (i = 0; i < MAX_ICH6_DEV; i++) {
+ for (i = 0; i < chip->num_streams; i++) {
azx_dev = &chip->azx_dev[i];
if (status & azx_dev->sd_int_sta_mask) {
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
@@ -873,9 +923,15 @@ static int __devinit azx_codec_create(azx_t *chip, const char *model)
/* assign a stream for the PCM */
static inline azx_dev_t *azx_assign_device(azx_t *chip, int stream)
{
- int dev, i;
- dev = stream == SNDRV_PCM_STREAM_PLAYBACK ? 4 : 0;
- for (i = 0; i < 4; i++, dev++)
+ int dev, i, nums;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dev = chip->playback_index_offset;
+ nums = chip->playback_streams;
+ } else {
+ dev = chip->capture_index_offset;
+ nums = chip->capture_streams;
+ }
+ for (i = 0; i < nums; i++, dev++)
if (! chip->azx_dev[dev].opened) {
chip->azx_dev[dev].opened = 1;
return &chip->azx_dev[dev];
@@ -893,8 +949,8 @@ static snd_pcm_hardware_t azx_pcm_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_RESUME),
+ SNDRV_PCM_INFO_PAUSE /*|*/
+ /*SNDRV_PCM_INFO_RESUME*/),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@@ -1043,6 +1099,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
azx_dev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
azx_stream_stop(chip, azx_dev);
azx_dev->running = 0;
@@ -1052,6 +1109,7 @@ static int azx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
}
spin_unlock(&chip->reg_lock);
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
+ cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
cmd == SNDRV_PCM_TRIGGER_STOP) {
int timeout = 5000;
while (azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START && --timeout)
@@ -1130,6 +1188,7 @@ static int __devinit create_codec_pcm(azx_t *chip, struct hda_codec *codec,
snd_dma_pci_data(chip->pci),
1024 * 64, 1024 * 128);
chip->pcm[pcm_dev] = pcm;
+ chip->pcm_devs = pcm_dev + 1;
return 0;
}
@@ -1180,7 +1239,7 @@ static int __devinit azx_init_stream(azx_t *chip)
/* initialize each stream (aka device)
* assign the starting bdl address to each stream (device) and initialize
*/
- for (i = 0; i < MAX_ICH6_DEV; i++) {
+ for (i = 0; i < chip->num_streams; i++) {
unsigned int off = sizeof(u32) * (i * AZX_MAX_FRAG * 4);
azx_dev_t *azx_dev = &chip->azx_dev[i];
azx_dev->bdl = (u32 *)(chip->bdl.area + off);
@@ -1239,7 +1298,7 @@ static int azx_free(azx_t *chip)
if (chip->initialized) {
int i;
- for (i = 0; i < MAX_ICH6_DEV; i++)
+ for (i = 0; i < chip->num_streams; i++)
azx_stream_stop(chip, &chip->azx_dev[i]);
/* disable interrupts */
@@ -1255,10 +1314,10 @@ static int azx_free(azx_t *chip)
/* wait a little for interrupts to finish */
msleep(1);
-
- iounmap(chip->remap_addr);
}
+ if (chip->remap_addr)
+ iounmap(chip->remap_addr);
if (chip->irq >= 0)
free_irq(chip->irq, (void*)chip);
@@ -1270,6 +1329,7 @@ static int azx_free(azx_t *chip)
snd_dma_free_pages(&chip->posbuf);
pci_release_regions(chip->pci);
pci_disable_device(chip->pci);
+ kfree(chip->azx_dev);
kfree(chip);
return 0;
@@ -1284,7 +1344,8 @@ static int azx_dev_free(snd_device_t *device)
* constructor
*/
static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
- int posfix, azx_t **rchip)
+ int posfix, int driver_type,
+ azx_t **rchip)
{
azx_t *chip;
int err = 0;
@@ -1310,9 +1371,20 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
chip->card = card;
chip->pci = pci;
chip->irq = -1;
+ chip->driver_type = driver_type;
chip->position_fix = posfix;
+#if BITS_PER_LONG != 64
+ /* Fix up base address on ULI M5461 */
+ if (chip->driver_type == AZX_DRIVER_ULI) {
+ u16 tmp3;
+ pci_read_config_word(pci, 0x40, &tmp3);
+ pci_write_config_word(pci, 0x40, tmp3 | 0x10);
+ pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
+ }
+#endif
+
if ((err = pci_request_regions(pci, "ICH HD audio")) < 0) {
kfree(chip);
pci_disable_device(pci);
@@ -1338,16 +1410,37 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
pci_set_master(pci);
synchronize_irq(chip->irq);
+ switch (chip->driver_type) {
+ case AZX_DRIVER_ULI:
+ chip->playback_streams = ULI_NUM_PLAYBACK;
+ chip->capture_streams = ULI_NUM_CAPTURE;
+ chip->playback_index_offset = ULI_PLAYBACK_INDEX;
+ chip->capture_index_offset = ULI_CAPTURE_INDEX;
+ break;
+ default:
+ chip->playback_streams = ICH6_NUM_PLAYBACK;
+ chip->capture_streams = ICH6_NUM_CAPTURE;
+ chip->playback_index_offset = ICH6_PLAYBACK_INDEX;
+ chip->capture_index_offset = ICH6_CAPTURE_INDEX;
+ break;
+ }
+ chip->num_streams = chip->playback_streams + chip->capture_streams;
+ chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL);
+ if (! chip->azx_dev) {
+ snd_printk(KERN_ERR "cannot malloc azx_dev\n");
+ goto errout;
+ }
+
/* allocate memory for the BDL for each stream */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
- PAGE_SIZE, &chip->bdl)) < 0) {
+ BDL_SIZE, &chip->bdl)) < 0) {
snd_printk(KERN_ERR SFX "cannot allocate BDL\n");
goto errout;
}
if (chip->position_fix == POS_FIX_POSBUF) {
/* allocate memory for the position buffer */
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
- MAX_ICH6_DEV * 8, &chip->posbuf)) < 0) {
+ chip->num_streams * 8, &chip->posbuf)) < 0) {
snd_printk(KERN_ERR SFX "cannot allocate posbuf\n");
goto errout;
}
@@ -1376,6 +1469,10 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci,
goto errout;
}
+ strcpy(card->driver, "HDA-Intel");
+ strcpy(card->shortname, driver_short_names[chip->driver_type]);
+ sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
+
*rchip = chip;
return 0;
@@ -1404,15 +1501,12 @@ static int __devinit azx_probe(struct pci_dev *pci, const struct pci_device_id *
return -ENOMEM;
}
- if ((err = azx_create(card, pci, position_fix[dev], &chip)) < 0) {
+ if ((err = azx_create(card, pci, position_fix[dev], pci_id->driver_data,
+ &chip)) < 0) {
snd_card_free(card);
return err;
}
- strcpy(card->driver, "HDA-Intel");
- strcpy(card->shortname, "HDA Intel");
- sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->addr, chip->irq);
-
/* create codec instances */
if ((err = azx_codec_create(chip, model[dev])) < 0) {
snd_card_free(card);
@@ -1453,12 +1547,13 @@ static void __devexit azx_remove(struct pci_dev *pci)
/* PCI IDs */
static struct pci_device_id azx_ids[] = {
- { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH6 */
- { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH7 */
- { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ESB2 */
- { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ATI SB450 */
- { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* VIA VT8251/VT8237A */
- { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ALI 5461? */
+ { 0x8086, 0x2668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH6 */
+ { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
+ { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
+ { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
+ { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */
+ { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */
+ { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h
index a5de684b6944..acaef3c811b8 100644
--- a/sound/pci/hda/hda_patch.h
+++ b/sound/pci/hda/hda_patch.h
@@ -10,11 +10,14 @@ extern struct hda_codec_preset snd_hda_preset_cmedia[];
extern struct hda_codec_preset snd_hda_preset_analog[];
/* SigmaTel codecs */
extern struct hda_codec_preset snd_hda_preset_sigmatel[];
+/* SiLabs 3054/3055 modem codecs */
+extern struct hda_codec_preset snd_hda_preset_si3054[];
static const struct hda_codec_preset *hda_preset_tables[] = {
snd_hda_preset_realtek,
snd_hda_preset_cmedia,
snd_hda_preset_analog,
snd_hda_preset_sigmatel,
+ snd_hda_preset_si3054,
NULL
};
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 2fd05bb84136..bceb83a42a38 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -572,7 +572,7 @@ static snd_kcontrol_new_t ad1983_mixers[] = {
},
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Playback Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,
@@ -705,7 +705,7 @@ static snd_kcontrol_new_t ad1981_mixers[] = {
/* identical with AD1983 */
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Playback Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = ad1983_spdif_route_info,
.get = ad1983_spdif_route_get,
.put = ad1983_spdif_route_put,
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 2d6e3e3d0a38..07fb4f5a54b3 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -408,7 +408,7 @@ static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct aut
/* search for an empty channel */
for (j = 0; j < cfg->line_outs; j++) {
if (! assigned[j]) {
- spec->dac_nids[i] = i + 0x03;
+ spec->dac_nids[i] = j + 0x03;
assigned[j] = 1;
break;
}
@@ -444,11 +444,10 @@ static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pi
len = snd_hda_get_connections(codec, nid, conn, 4);
for (k = 0; k < len; k++)
if (conn[k] == spec->dac_nids[i]) {
- spec->multi_init[j].param = j;
+ spec->multi_init[j].param = k;
break;
}
j++;
- break;
}
}
return 0;
@@ -648,6 +647,7 @@ static struct hda_board_config cmi9880_cfg_tbl[] = {
{ .modelname = "min_fp", .config = CMI_MIN_FP },
{ .modelname = "full", .config = CMI_FULL },
{ .modelname = "full_dig", .config = CMI_FULL_DIG },
+ { .pci_subvendor = 0x1043, .pci_subdevice = 0x813d, .config = CMI_FULL_DIG }, /* ASUS P5AD2 */
{ .modelname = "allout", .config = CMI_ALLOUT },
{ .modelname = "auto", .config = CMI_AUTO },
{} /* terminator */
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bab89843d850..eeb900ab79af 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -40,6 +40,7 @@ enum {
ALC880_W810,
ALC880_Z71V,
ALC880_AUTO,
+ ALC880_6ST,
ALC880_6ST_DIG,
ALC880_F1734,
ALC880_ASUS,
@@ -119,6 +120,7 @@ struct alc_spec {
unsigned int num_kctl_alloc, num_kctl_used;
snd_kcontrol_new_t *kctl_alloc;
struct hda_input_mux private_imux;
+ hda_nid_t private_dac_nids[4];
};
@@ -685,6 +687,12 @@ static snd_kcontrol_new_t alc880_asus_w1v_mixer[] = {
{ } /* end */
};
+/* additional mixers to alc880_asus_mixer */
+static snd_kcontrol_new_t alc880_pcbeep_mixer[] = {
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ { } /* end */
+};
/*
* build control elements
@@ -1522,6 +1530,7 @@ static struct hda_board_config alc880_cfg_tbl[] = {
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack */
{ .modelname = "3stack-digout", .config = ALC880_3ST_DIG },
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe308, .config = ALC880_3ST_DIG },
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0x0070, .config = ALC880_3ST_DIG },
/* Back 3 jack plus 1 SPDIF out jack, front 2 jack (Internal add Aux-In)*/
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xe305, .config = ALC880_3ST_DIG },
@@ -1547,9 +1556,10 @@ static struct hda_board_config alc880_cfg_tbl[] = {
{ .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
{ .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG },
+ /* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
{ .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
- { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG },
+ /* note subvendor = 0 below */
+ /* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
{ .modelname = "w810", .config = ALC880_W810 },
{ .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
@@ -1557,7 +1567,10 @@ static struct hda_board_config alc880_cfg_tbl[] = {
{ .modelname = "z71v", .config = ALC880_Z71V },
{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
- { .modelname = "6statack-digout", .config = ALC880_6ST_DIG },
+ { .modelname = "6stack", .config = ALC880_6ST },
+ { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
+
+ { .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
{ .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
{ .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
{ .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
@@ -1644,6 +1657,15 @@ static struct alc_config_preset alc880_presets[] = {
.channel_mode = alc880_fivestack_modes,
.input_mux = &alc880_capture_source,
},
+ [ALC880_6ST] = {
+ .mixers = { alc880_six_stack_mixer },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
+ .dac_nids = alc880_6st_dac_nids,
+ .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
+ .channel_mode = alc880_sixstack_modes,
+ .input_mux = &alc880_6stack_capture_source,
+ },
[ALC880_6ST_DIG] = {
.mixers = { alc880_six_stack_mixer },
.init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
@@ -1656,7 +1678,8 @@ static struct alc_config_preset alc880_presets[] = {
},
[ALC880_W810] = {
.mixers = { alc880_w810_base_mixer },
- .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs,
+ alc880_gpio2_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
.dac_nids = alc880_w810_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
@@ -1666,8 +1689,7 @@ static struct alc_config_preset alc880_presets[] = {
},
[ALC880_Z71V] = {
.mixers = { alc880_z71v_mixer },
- .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs,
- alc880_gpio2_init_verbs },
+ .init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
.dac_nids = alc880_z71v_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
@@ -1719,7 +1741,7 @@ static struct alc_config_preset alc880_presets[] = {
.input_mux = &alc880_capture_source,
},
[ALC880_UNIWILL_DIG] = {
- .mixers = { alc880_asus_mixer },
+ .mixers = { alc880_asus_mixer, alc880_pcbeep_mixer },
.init_verbs = { alc880_volume_init_verbs, alc880_pin_asus_init_verbs },
.num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
.dac_nids = alc880_asus_dac_nids,
@@ -1809,6 +1831,7 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, const struct auto_pi
int i, j;
memset(assigned, 0, sizeof(assigned));
+ spec->multiout.dac_nids = spec->private_dac_nids;
/* check the pins hardwired to audio widget */
for (i = 0; i < cfg->line_outs; i++) {
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
new file mode 100644
index 000000000000..b0270d1b64ce
--- /dev/null
+++ b/sound/pci/hda/patch_si3054.c
@@ -0,0 +1,300 @@
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ *
+ * Copyright (c) 2005 Sasha Khapyorsky <sashak@smlink.com>
+ * Takashi Iwai <tiwai@suse.de>
+ *
+ *
+ * This driver 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 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+
+
+/* si3054 verbs */
+#define SI3054_VERB_READ_NODE 0x900
+#define SI3054_VERB_WRITE_NODE 0x100
+
+/* si3054 nodes (registers) */
+#define SI3054_EXTENDED_MID 2
+#define SI3054_LINE_RATE 3
+#define SI3054_LINE_LEVEL 4
+#define SI3054_GPIO_CFG 5
+#define SI3054_GPIO_POLARITY 6
+#define SI3054_GPIO_STICKY 7
+#define SI3054_GPIO_WAKEUP 8
+#define SI3054_GPIO_STATUS 9
+#define SI3054_GPIO_CONTROL 10
+#define SI3054_MISC_AFE 11
+#define SI3054_CHIPID 12
+#define SI3054_LINE_CFG1 13
+#define SI3054_LINE_STATUS 14
+#define SI3054_DC_TERMINATION 15
+#define SI3054_LINE_CONFIG 16
+#define SI3054_CALLPROG_ATT 17
+#define SI3054_SQ_CONTROL 18
+#define SI3054_MISC_CONTROL 19
+#define SI3054_RING_CTRL1 20
+#define SI3054_RING_CTRL2 21
+
+/* extended MID */
+#define SI3054_MEI_READY 0xf
+
+/* line level */
+#define SI3054_ATAG_MASK 0x00f0
+#define SI3054_DTAG_MASK 0xf000
+
+/* GPIO bits */
+#define SI3054_GPIO_OH 0x0001
+#define SI3054_GPIO_CID 0x0002
+
+/* chipid and revisions */
+#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
+#define SI3054_CHIPID_DAA_REV_MASK 0x00f0
+#define SI3054_CHIPID_INTERNATIONAL 0x0100
+#define SI3054_CHIPID_DAA_ID 0x0f00
+#define SI3054_CHIPID_CODEC_ID (1<<12)
+
+/* si3054 codec registers (nodes) access macros */
+#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
+#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
+
+
+struct si3054_spec {
+ unsigned international;
+ struct hda_pcm pcm;
+};
+
+
+/*
+ * Modem mixer
+ */
+
+#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
+#define PRIVATE_REG(val) ((val>>16)&0xffff)
+#define PRIVATE_MASK(val) (val&0xffff)
+
+static int si3054_switch_info(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int si3054_switch_get(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *uvalue)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 reg = PRIVATE_REG(kcontrol->private_value);
+ u16 mask = PRIVATE_MASK(kcontrol->private_value);
+ uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
+ return 0;
+}
+
+static int si3054_switch_put(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *uvalue)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 reg = PRIVATE_REG(kcontrol->private_value);
+ u16 mask = PRIVATE_MASK(kcontrol->private_value);
+ if (uvalue->value.integer.value[0])
+ SET_REG(codec, reg, (GET_REG(codec, reg)) | mask);
+ else
+ SET_REG(codec, reg, (GET_REG(codec, reg)) & ~mask);
+ return 0;
+}
+
+#define SI3054_KCONTROL(kname,reg,mask) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = kname, \
+ .info = si3054_switch_info, \
+ .get = si3054_switch_get, \
+ .put = si3054_switch_put, \
+ .private_value = PRIVATE_VALUE(reg,mask), \
+}
+
+
+static snd_kcontrol_new_t si3054_modem_mixer[] = {
+ SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
+ SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
+ {}
+};
+
+static int si3054_build_controls(struct hda_codec *codec)
+{
+ return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
+}
+
+
+/*
+ * PCM callbacks
+ */
+
+static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ snd_pcm_substream_t *substream)
+{
+ u16 val;
+
+ SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
+ val = GET_REG(codec, SI3054_LINE_LEVEL);
+ val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
+ val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
+ SET_REG(codec, SI3054_LINE_LEVEL, val);
+
+ snd_hda_codec_setup_stream(codec, hinfo->nid,
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
+{
+ static unsigned int rates[] = { 8000, 9600, 16000 };
+ static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+ };
+ substream->runtime->hw.period_bytes_min = 80;
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+}
+
+
+static struct hda_pcm_stream si3054_pcm = {
+ .substreams = 1,
+ .channels_min = 1,
+ .channels_max = 1,
+ .nid = 0x1,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .maxbps = 16,
+ .ops = {
+ .open = si3054_pcm_open,
+ .prepare = si3054_pcm_prepare,
+ },
+};
+
+
+static int si3054_build_pcms(struct hda_codec *codec)
+{
+ struct si3054_spec *spec = codec->spec;
+ struct hda_pcm *info = &spec->pcm;
+ si3054_pcm.nid = codec->mfg;
+ codec->num_pcms = 1;
+ codec->pcm_info = info;
+ info->name = "Si3054 Modem";
+ info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm;
+ return 0;
+}
+
+
+/*
+ * Init part
+ */
+
+static int si3054_init(struct hda_codec *codec)
+{
+ struct si3054_spec *spec = codec->spec;
+ unsigned wait_count;
+ u16 val;
+
+ snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
+ snd_hda_codec_write(codec, codec->mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+ SET_REG(codec, SI3054_LINE_RATE, 9600);
+ SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
+ SET_REG(codec, SI3054_EXTENDED_MID, 0);
+
+ wait_count = 10;
+ do {
+ msleep(2);
+ val = GET_REG(codec, SI3054_EXTENDED_MID);
+ } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
+
+ if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
+ snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val);
+ return -EACCES;
+ }
+
+ SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
+ SET_REG(codec, SI3054_GPIO_CFG, 0x0);
+ SET_REG(codec, SI3054_MISC_AFE, 0);
+ SET_REG(codec, SI3054_LINE_CFG1,0x200);
+
+ if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
+ snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+ GET_REG(codec,SI3054_LINE_STATUS));
+ }
+
+ spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
+
+ return 0;
+}
+
+static void si3054_free(struct hda_codec *codec)
+{
+ kfree(codec->spec);
+}
+
+
+/*
+ */
+
+static struct hda_codec_ops si3054_patch_ops = {
+ .build_controls = si3054_build_controls,
+ .build_pcms = si3054_build_pcms,
+ .init = si3054_init,
+ .free = si3054_free,
+#ifdef CONFIG_PM
+ //.suspend = si3054_suspend,
+ .resume = si3054_init,
+#endif
+};
+
+static int patch_si3054(struct hda_codec *codec)
+{
+ struct si3054_spec *spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+ codec->spec = spec;
+ codec->patch_ops = si3054_patch_ops;
+ return 0;
+}
+
+/*
+ * patch entries
+ */
+struct hda_codec_preset snd_hda_preset_si3054[] = {
+ { .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
+ {}
+};
+
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 013be2ea513a..9d503da7320d 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -30,32 +30,37 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <sound/core.h>
+#include <sound/asoundef.h>
#include "hda_codec.h"
#include "hda_local.h"
#undef STAC_TEST
+#define NUM_CONTROL_ALLOC 32
+#define STAC_HP_EVENT 0x37
+#define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT)
+
struct sigmatel_spec {
+ snd_kcontrol_new_t *mixers[4];
+ unsigned int num_mixers;
+
+ unsigned int surr_switch: 1;
+
/* playback */
struct hda_multi_out multiout;
- hda_nid_t playback_nid;
+ hda_nid_t dac_nids[4];
/* capture */
hda_nid_t *adc_nids;
unsigned int num_adcs;
hda_nid_t *mux_nids;
unsigned int num_muxes;
- hda_nid_t capture_nid;
hda_nid_t dig_in_nid;
- /* power management*/
- hda_nid_t *pstate_nids;
- unsigned int num_pstates;
-
+#ifdef STAC_TEST
/* pin widgets */
hda_nid_t *pin_nids;
unsigned int num_pins;
-#ifdef STAC_TEST
unsigned int *pin_configs;
#endif
@@ -64,16 +69,20 @@ struct sigmatel_spec {
snd_kcontrol_new_t *mixer;
/* capture source */
- struct hda_input_mux input_mux;
- char input_labels[HDA_MAX_NUM_INPUTS][16];
+ struct hda_input_mux *input_mux;
unsigned int cur_mux[2];
/* channel mode */
unsigned int num_ch_modes;
unsigned int cur_ch_mode;
- const struct sigmatel_channel_mode *channel_modes;
- struct hda_pcm pcm_rec[1]; /* PCM information */
+ struct hda_pcm pcm_rec[2]; /* PCM information */
+
+ /* dynamic controls and input_mux */
+ struct auto_pin_cfg autocfg;
+ unsigned int num_kctl_alloc, num_kctl_used;
+ snd_kcontrol_new_t *kctl_alloc;
+ struct hda_input_mux private_imux;
};
static hda_nid_t stac9200_adc_nids[1] = {
@@ -88,14 +97,6 @@ static hda_nid_t stac9200_dac_nids[1] = {
0x02,
};
-static hda_nid_t stac9200_pstate_nids[3] = {
- 0x01, 0x02, 0x03,
-};
-
-static hda_nid_t stac9200_pin_nids[8] = {
- 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
-};
-
static hda_nid_t stac922x_adc_nids[2] = {
0x06, 0x07,
};
@@ -104,24 +105,22 @@ static hda_nid_t stac922x_mux_nids[2] = {
0x12, 0x13,
};
-static hda_nid_t stac922x_dac_nids[4] = {
- 0x02, 0x03, 0x04, 0x05,
-};
-
-static hda_nid_t stac922x_pstate_nids[8] = {
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11,
+#ifdef STAC_TEST
+static hda_nid_t stac9200_pin_nids[8] = {
+ 0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
};
static hda_nid_t stac922x_pin_nids[10] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x15, 0x1b,
};
+#endif
static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
- return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+ return snd_hda_input_mux_info(spec->input_mux, uinfo);
}
static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
@@ -140,26 +139,64 @@ static int stac92xx_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
struct sigmatel_spec *spec = codec->spec;
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+ return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
}
-static struct hda_verb stac9200_ch2_init[] = {
+static struct hda_verb stac9200_core_init[] = {
/* set dac0mux for dac converter */
- { 0x07, 0x701, 0x00},
+ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
{}
};
-static struct hda_verb stac922x_ch2_init[] = {
+static struct hda_verb stac922x_core_init[] = {
/* set master volume and direct control */
- { 0x16, 0x70f, 0xff},
+ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
{}
};
-struct sigmatel_channel_mode {
- unsigned int channels;
- const struct hda_verb *sequence;
-};
+static int stac922x_channel_modes[3] = {2, 6, 8};
+
+static int stac922x_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = spec->num_ch_modes;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ sprintf(uinfo->value.enumerated.name, "%dch",
+ stac922x_channel_modes[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+static int stac922x_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
+ return 0;
+}
+
+static int stac922x_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+
+ if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
+ ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
+ if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
+ ! codec->in_resume)
+ return 0;
+
+ spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
+ spec->multiout.max_channels = stac922x_channel_modes[spec->cur_ch_mode];
+
+ return 1;
+}
static snd_kcontrol_new_t stac9200_mixer[] = {
HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
@@ -174,13 +211,12 @@ static snd_kcontrol_new_t stac9200_mixer[] = {
},
HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
{ } /* end */
};
+/* This needs to be generated dynamically based on sequence */
static snd_kcontrol_new_t stac922x_mixer[] = {
- HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -195,14 +231,38 @@ static snd_kcontrol_new_t stac922x_mixer[] = {
{ } /* end */
};
+static snd_kcontrol_new_t stac922x_ch_mode_mixer[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = stac922x_ch_mode_info,
+ .get = stac922x_ch_mode_get,
+ .put = stac922x_ch_mode_put,
+ },
+ { } /* end */
+};
+
static int stac92xx_build_controls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
int err;
+ int i;
err = snd_hda_add_new_ctls(codec, spec->mixer);
if (err < 0)
return err;
+
+ for (i = 0; i < spec->num_mixers; i++) {
+ err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+ if (err < 0)
+ return err;
+ }
+
+ if (spec->surr_switch) {
+ err = snd_hda_add_new_ctls(codec, stac922x_ch_mode_mixer);
+ if (err < 0)
+ return err;
+ }
if (spec->multiout.dig_out_nid) {
err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
if (err < 0)
@@ -222,9 +282,9 @@ static unsigned int stac9200_pin_configs[8] = {
0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
};
-static unsigned int stac922x_pin_configs[14] = {
- 0x40000100, 0x40000100, 0x40000100, 0x01114010,
- 0x01813122, 0x40000100, 0x01447010, 0x01c47010,
+static unsigned int stac922x_pin_configs[10] = {
+ 0x01014010, 0x01014011, 0x01014012, 0x0221401f,
+ 0x01813122, 0x01014014, 0x01441030, 0x01c41030,
0x40000100, 0x40000100,
};
@@ -255,180 +315,66 @@ static void stac92xx_set_config_regs(struct hda_codec *codec)
}
#endif
-static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value)
-{
- unsigned int pin_ctl;
-
- pin_ctl = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL,
- 0x00);
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_ctl | value);
-
- return 0;
-}
-
-static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid)
-{
- unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT;
- unsigned int vref_ctl = AC_PINCTL_VREF_HIZ;
-
- if (vref_caps & AC_PINCAP_VREF_100)
- vref_ctl = AC_PINCTL_VREF_100;
- else if (vref_caps & AC_PINCAP_VREF_80)
- vref_ctl = AC_PINCTL_VREF_80;
- else if (vref_caps & AC_PINCAP_VREF_50)
- vref_ctl = AC_PINCTL_VREF_50;
- else if (vref_caps & AC_PINCAP_VREF_GRD)
- vref_ctl = AC_PINCTL_VREF_GRD;
-
- stac92xx_set_pinctl(codec, nid, vref_ctl);
-
- return 0;
-}
-
/*
- * retrieve the default device type from the default config value
+ * Analog playback callbacks
*/
-#define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
-#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
-
-static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg)
+static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ snd_pcm_substream_t *substream)
{
struct sigmatel_spec *spec = codec->spec;
- u32 location = get_defcfg_location(pin_cfg);
- char *label;
- const char *type = NULL;
- int ainput = 0;
-
- switch(get_defcfg_type(pin_cfg)) {
- case AC_JACK_HP_OUT:
- /* Enable HP amp */
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN);
- /* Fall through */
- case AC_JACK_SPDIF_OUT:
- case AC_JACK_LINE_OUT:
- case AC_JACK_SPEAKER:
- /* Enable output */
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
- break;
- case AC_JACK_SPDIF_IN:
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
- break;
- case AC_JACK_MIC_IN:
- if ((location & 0x0f) == AC_JACK_LOC_FRONT)
- type = "Front Mic";
- else
- type = "Mic";
- ainput = 1;
- /* Set vref */
- stac92xx_set_vref(codec, nid);
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
- break;
- case AC_JACK_CD:
- type = "CD";
- ainput = 1;
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
- break;
- case AC_JACK_LINE_IN:
- if ((location & 0x0f) == AC_JACK_LOC_FRONT)
- type = "Front Line";
- else
- type = "Line";
- ainput = 1;
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
- break;
- case AC_JACK_AUX:
- if ((location & 0x0f) == AC_JACK_LOC_FRONT)
- type = "Front Aux";
- else
- type = "Aux";
- ainput = 1;
- stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
- break;
- }
-
- if (ainput) {
- hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
- int i, j, num_cons, index = -1;
- if (!type)
- type = "Input";
- label = spec->input_labels[spec->input_mux.num_items];
- strcpy(label, type);
- spec->input_mux.items[spec->input_mux.num_items].label = label;
- for (i=0; i<spec->num_muxes; i++) {
- num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS);
- for (j=0; j<num_cons; j++)
- if (con_lst[j] == nid) {
- index = j;
- break;
- }
- if (index >= 0)
- break;
- }
- spec->input_mux.items[spec->input_mux.num_items].index = index;
- spec->input_mux.num_items++;
- }
-
- return 0;
+ return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
}
-static int stac92xx_config_pins(struct hda_codec *codec)
+/*
+ * set up the i/o for analog out
+ * when the digital out is available, copy the front out to digital out, too.
+ */
+static int stac92xx_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+ unsigned int stream_tag,
+ unsigned int format,
+ snd_pcm_substream_t *substream)
{
- struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t *nids = mout->dac_nids;
+ int chs = substream->runtime->channels;
int i;
- unsigned int pin_cfg;
- for (i=0; i < spec->num_pins; i++) {
- /* Default to disabled */
- snd_hda_codec_write(codec, spec->pin_nids[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- 0x00);
-
- pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
- AC_VERB_GET_CONFIG_DEFAULT,
- 0x00);
- if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE)
- continue; /* Move on */
-
- stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg);
+ down(&codec->spdif_mutex);
+ if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+ if (chs == 2 &&
+ snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
+ ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+ mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+ /* setup digital receiver */
+ snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+ stream_tag, 0, format);
+ } else {
+ mout->dig_out_used = 0;
+ snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+ }
}
-
- return 0;
-}
-
-static int stac92xx_init(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
- int i;
-
- for (i=0; i < spec->num_pstates; i++)
- snd_hda_codec_write(codec, spec->pstate_nids[i], 0,
- AC_VERB_SET_POWER_STATE, 0x00);
-
- mdelay(100);
-
- snd_hda_sequence_write(codec, spec->init);
-
-#ifdef STAC_TEST
- stac92xx_set_config_regs(codec);
-#endif
-
- stac92xx_config_pins(codec);
-
+ up(&codec->spdif_mutex);
+
+ /* front */
+ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
+ if (mout->hp_nid)
+ /* headphone out will just decode front left/right (stereo) */
+ snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
+ /* surrounds */
+ if (mout->max_channels > 2)
+ for (i = 1; i < mout->num_dacs; i++) {
+ if ((mout->max_channels == 6) && (i == 3))
+ break;
+ if (chs >= (i + 1) * 2) /* independent out */
+ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,
+ format);
+ else /* copy front */
+ snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0,
+ format);
+ }
return 0;
}
-/*
- * Analog playback callbacks
- */
-static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- snd_pcm_substream_t *substream)
-{
- struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
-}
static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
@@ -437,7 +383,7 @@ static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
snd_pcm_substream_t *substream)
{
struct sigmatel_spec *spec = codec->spec;
- return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+ return stac92xx_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
format, substream);
}
@@ -516,7 +462,7 @@ static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
.substreams = 1,
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 8,
.nid = 0x02, /* NID to query formats and rates */
.ops = {
.open = stac92xx_playback_pcm_open,
@@ -544,11 +490,9 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
codec->num_pcms = 1;
codec->pcm_info = info;
- info->name = "STAC92xx";
+ info->name = "STAC92xx Analog";
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
- info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid;
info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
- info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid;
if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
codec->num_pcms++;
@@ -567,21 +511,413 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return 0;
}
+enum {
+ STAC_CTL_WIDGET_VOL,
+ STAC_CTL_WIDGET_MUTE,
+};
+
+static snd_kcontrol_new_t stac92xx_control_templates[] = {
+ HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+ HDA_CODEC_MUTE(NULL, 0, 0, 0),
+};
+
+/* add dynamic controls */
+static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
+{
+ snd_kcontrol_new_t *knew;
+
+ if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+ int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+ knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
+ if (! knew)
+ return -ENOMEM;
+ if (spec->kctl_alloc) {
+ memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
+ kfree(spec->kctl_alloc);
+ }
+ spec->kctl_alloc = knew;
+ spec->num_kctl_alloc = num;
+ }
+
+ knew = &spec->kctl_alloc[spec->num_kctl_used];
+ *knew = stac92xx_control_templates[type];
+ knew->name = kstrdup(name, GFP_KERNEL);
+ if (! knew->name)
+ return -ENOMEM;
+ knew->private_value = val;
+ spec->num_kctl_used++;
+ return 0;
+}
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t nid;
+ int i;
+
+ /* check the pins hardwired to audio widget */
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = cfg->line_out_pins[i];
+ spec->multiout.dac_nids[i] = snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+ }
+
+ spec->multiout.num_dacs = cfg->line_outs;
+
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg)
+{
+ char name[32];
+ static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+ hda_nid_t nid;
+ int i, err;
+
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (! spec->multiout.dac_nids[i])
+ continue;
+
+ nid = spec->multiout.dac_nids[i];
+
+ if (i == 2) {
+ /* Center/LFE */
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+ return err;
+ } else {
+ sprintf(name, "%s Playback Volume", chname[i]);
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ sprintf(name, "%s Playback Switch", chname[i]);
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/* add playback controls for HP output */
+static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t pin = cfg->hp_pin;
+ hda_nid_t nid;
+ int i, err;
+ unsigned int wid_caps;
+
+ if (! pin)
+ return 0;
+
+ wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP);
+ if (wid_caps & AC_WCAP_UNSOL_CAP)
+ /* Enable unsolicited responses on the HP widget */
+ snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ STAC_UNSOL_ENABLE);
+
+ nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+ for (i = 0; i < cfg->line_outs; i++) {
+ if (! spec->multiout.dac_nids[i])
+ continue;
+ if (spec->multiout.dac_nids[i] == nid)
+ return 0;
+ }
+
+ spec->multiout.hp_nid = nid;
+
+ /* control HP volume/switch on the output mixer amp */
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+ if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+ return err;
+
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ static char *labels[AUTO_PIN_LAST] = {
+ "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
+ };
+ struct hda_input_mux *imux = &spec->private_imux;
+ hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+ int i, j, k;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ int index = -1;
+ if (cfg->input_pins[i]) {
+ imux->items[imux->num_items].label = labels[i];
+
+ for (j=0; j<spec->num_muxes; j++) {
+ int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS);
+ for (k=0; k<num_cons; k++)
+ if (con_lst[k] == cfg->input_pins[i]) {
+ index = k;
+ break;
+ }
+ if (index >= 0)
+ break;
+ }
+ imux->items[imux->num_items].index = index;
+ imux->num_items++;
+ }
+ }
+
+ return 0;
+}
+
+static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
+
+{
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+}
+
+static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ for (i = 0; i < spec->autocfg.line_outs; i++) {
+ hda_nid_t nid = spec->autocfg.line_out_pins[i];
+ stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
+ }
+}
+
+static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ hda_nid_t pin;
+
+ pin = spec->autocfg.hp_pin;
+ if (pin) /* connect to front */
+ stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+}
+
+static int stac922x_parse_auto_config(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int err;
+
+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+ return err;
+ if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+ return err;
+ if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
+ return 0; /* can't find valid pin config */
+
+ if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
+ (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 ||
+ (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
+ return err;
+
+ spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+ if (spec->multiout.max_channels > 2) {
+ spec->surr_switch = 1;
+ spec->cur_ch_mode = 1;
+ spec->num_ch_modes = 2;
+ if (spec->multiout.max_channels == 8) {
+ spec->cur_ch_mode++;
+ spec->num_ch_modes++;
+ }
+ }
+
+ if (spec->autocfg.dig_out_pin) {
+ spec->multiout.dig_out_nid = 0x08;
+ stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
+ }
+ if (spec->autocfg.dig_in_pin) {
+ spec->dig_in_nid = 0x09;
+ stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
+ }
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+static int stac9200_parse_auto_config(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int err;
+
+ if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+ return err;
+
+ if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
+ return err;
+
+ if (spec->autocfg.dig_out_pin) {
+ spec->multiout.dig_out_nid = 0x05;
+ stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
+ }
+ if (spec->autocfg.dig_in_pin) {
+ spec->dig_in_nid = 0x04;
+ stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
+ }
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+static int stac92xx_init_pstate(struct hda_codec *codec)
+{
+ hda_nid_t nid, nid_start;
+ int nodes;
+
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_POWER_STATE, 0x00);
+
+ nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
+ for (nid = nid_start; nid < nodes + nid_start; nid++) {
+ unsigned int wid_caps = snd_hda_param_read(codec, nid,
+ AC_PAR_AUDIO_WIDGET_CAP);
+ if (wid_caps & AC_WCAP_POWER)
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_POWER_STATE, 0x00);
+ }
+
+ mdelay(100);
+
+ return 0;
+}
+
+static int stac92xx_init(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+
+ stac92xx_init_pstate(codec);
+
+ snd_hda_sequence_write(codec, spec->init);
+
+ stac92xx_auto_init_multi_out(codec);
+ stac92xx_auto_init_hp_out(codec);
+
+ return 0;
+}
+
static void stac92xx_free(struct hda_codec *codec)
{
- kfree(codec->spec);
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ if (! spec)
+ return;
+
+ if (spec->kctl_alloc) {
+ for (i = 0; i < spec->num_kctl_used; i++)
+ kfree(spec->kctl_alloc[i].name);
+ kfree(spec->kctl_alloc);
+ }
+
+ kfree(spec);
+}
+
+static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int flag)
+{
+ unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl | flag);
+}
+
+static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int flag)
+{
+ unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
+ snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pin_ctl & ~flag);
+}
+
+static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int i, presence;
+
+ if ((res >> 26) != STAC_HP_EVENT)
+ return;
+
+ presence = snd_hda_codec_read(codec, cfg->hp_pin, 0,
+ AC_VERB_GET_PIN_SENSE, 0x00) >> 31;
+
+ if (presence) {
+ /* disable lineouts, enable hp */
+ for (i = 0; i < cfg->line_outs; i++)
+ stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
+ AC_PINCTL_OUT_EN);
+ stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
+ } else {
+ /* enable lineouts, disable hp */
+ for (i = 0; i < cfg->line_outs; i++)
+ stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
+ AC_PINCTL_OUT_EN);
+ stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
+ }
+}
+
+#ifdef CONFIG_PM
+static int stac92xx_resume(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ int i;
+
+ stac92xx_init(codec);
+ for (i = 0; i < spec->num_mixers; i++)
+ snd_hda_resume_ctls(codec, spec->mixers[i]);
+ if (spec->multiout.dig_out_nid)
+ snd_hda_resume_spdif_out(codec);
+ if (spec->dig_in_nid)
+ snd_hda_resume_spdif_in(codec);
+
+ return 0;
}
+#endif
static struct hda_codec_ops stac92xx_patch_ops = {
.build_controls = stac92xx_build_controls,
.build_pcms = stac92xx_build_pcms,
.init = stac92xx_init,
.free = stac92xx_free,
+ .unsol_event = stac92xx_unsol_event,
+#ifdef CONFIG_PM
+ .resume = stac92xx_resume,
+#endif
};
static int patch_stac9200(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
+ int err;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -589,26 +925,27 @@ static int patch_stac9200(struct hda_codec *codec)
codec->spec = spec;
+#ifdef STAC_TEST
+ spec->pin_nids = stac9200_pin_nids;
+ spec->num_pins = 8;
+ spec->pin_configs = stac9200_pin_configs;
+ stac92xx_set_config_regs(codec);
+#endif
spec->multiout.max_channels = 2;
spec->multiout.num_dacs = 1;
spec->multiout.dac_nids = stac9200_dac_nids;
- spec->multiout.dig_out_nid = 0x05;
- spec->dig_in_nid = 0x04;
spec->adc_nids = stac9200_adc_nids;
spec->mux_nids = stac9200_mux_nids;
spec->num_muxes = 1;
- spec->input_mux.num_items = 0;
- spec->pstate_nids = stac9200_pstate_nids;
- spec->num_pstates = 3;
- spec->pin_nids = stac9200_pin_nids;
-#ifdef STAC_TEST
- spec->pin_configs = stac9200_pin_configs;
-#endif
- spec->num_pins = 8;
- spec->init = stac9200_ch2_init;
+
+ spec->init = stac9200_core_init;
spec->mixer = stac9200_mixer;
- spec->playback_nid = 0x02;
- spec->capture_nid = 0x03;
+
+ err = stac9200_parse_auto_config(codec);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
codec->patch_ops = stac92xx_patch_ops;
@@ -618,6 +955,7 @@ static int patch_stac9200(struct hda_codec *codec)
static int patch_stac922x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
+ int err;
spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
@@ -625,26 +963,26 @@ static int patch_stac922x(struct hda_codec *codec)
codec->spec = spec;
- spec->multiout.max_channels = 2;
- spec->multiout.num_dacs = 4;
- spec->multiout.dac_nids = stac922x_dac_nids;
- spec->multiout.dig_out_nid = 0x08;
- spec->dig_in_nid = 0x09;
- spec->adc_nids = stac922x_adc_nids;
- spec->mux_nids = stac922x_mux_nids;
- spec->num_muxes = 2;
- spec->input_mux.num_items = 0;
- spec->pstate_nids = stac922x_pstate_nids;
- spec->num_pstates = 8;
- spec->pin_nids = stac922x_pin_nids;
#ifdef STAC_TEST
+ spec->num_pins = 10;
+ spec->pin_nids = stac922x_pin_nids;
spec->pin_configs = stac922x_pin_configs;
+ stac92xx_set_config_regs(codec);
#endif
- spec->num_pins = 10;
- spec->init = stac922x_ch2_init;
+ spec->adc_nids = stac922x_adc_nids;
+ spec->mux_nids = stac922x_mux_nids;
+ spec->num_muxes = 2;
+
+ spec->init = stac922x_core_init;
spec->mixer = stac922x_mixer;
- spec->playback_nid = 0x02;
- spec->capture_nid = 0x06;
+
+ spec->multiout.dac_nids = spec->dac_nids;
+
+ err = stac922x_parse_auto_config(codec);
+ if (err < 0) {
+ stac92xx_free(codec);
+ return err;
+ }
codec->patch_ops = stac92xx_patch_ops;
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index eb20f73be61a..39fbe662965d 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -618,15 +618,15 @@ static int __devinit snd_ice1712_delta_init(ice1712_t *ice)
*/
static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
static snd_kcontrol_new_t snd_ice1712_delta1010lt_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
static snd_kcontrol_new_t snd_ice1712_delta1010_wordclock_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
static snd_kcontrol_new_t snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0);
static snd_kcontrol_new_t snd_ice1712_delta_spdif_in_status __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_PCM, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
static int __devinit snd_ice1712_delta_add_controls(ice1712_t *ice)
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index a2545a5b26c4..b97f50d10ba3 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -1422,7 +1422,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata
static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Multi Capture Switch",
+ .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,SWITCH),
.info = snd_ice1712_pro_mixer_switch_info,
.get = snd_ice1712_pro_mixer_switch_get,
.put = snd_ice1712_pro_mixer_switch_put,
@@ -1441,7 +1441,7 @@ static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata
static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Multi Capture Volume",
+ .name = SNDRV_CTL_NAME_IEC958("Multi ",CAPTURE,VOLUME),
.info = snd_ice1712_pro_mixer_volume_info,
.get = snd_ice1712_pro_mixer_volume_get,
.put = snd_ice1712_pro_mixer_volume_put,
@@ -1715,7 +1715,7 @@ static int snd_ice1712_spdif_maskp_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_ice1712_spdif_info,
.get = snd_ice1712_spdif_maskc_get,
@@ -1724,7 +1724,7 @@ static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_ice1712_spdif_info,
.get = snd_ice1712_spdif_maskp_get,
@@ -2203,7 +2203,7 @@ static snd_kcontrol_new_t snd_ice1712_mixer_pro_analog_route __devinitdata = {
static snd_kcontrol_new_t snd_ice1712_mixer_pro_spdif_route __devinitdata = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "IEC958 Playback Route",
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route",
.info = snd_ice1712_pro_route_info,
.get = snd_ice1712_pro_route_spdif_get,
.put = snd_ice1712_pro_route_spdif_put,
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 79b5f12e06fc..c7af5e5fee13 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -1414,7 +1414,7 @@ static int snd_vt1724_spdif_maskp_get(snd_kcontrol_t * kcontrol,
static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_vt1724_spdif_info,
.get = snd_vt1724_spdif_maskc_get,
@@ -1423,7 +1423,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_maskc __devinitdata =
static snd_kcontrol_new_t snd_vt1724_spdif_maskp __devinitdata =
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_vt1724_spdif_info,
.get = snd_vt1724_spdif_maskp_get,
@@ -1466,7 +1466,7 @@ static snd_kcontrol_new_t snd_vt1724_spdif_switch __devinitdata =
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
/* FIXME: the following conflict with IEC958 Playback Route */
// .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),
- .name = "IEC958 Output Switch",
+ .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.info = snd_vt1724_spdif_sw_info,
.get = snd_vt1724_spdif_sw_get,
.put = snd_vt1724_spdif_sw_put
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index cc16f95f9cef..7b548416dcef 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -389,6 +389,7 @@ typedef struct {
struct ac97_pcm *pcm;
int pcm_open_flag;
unsigned int page_attr_changed: 1;
+ unsigned int suspended: 1;
} ichdev_t;
typedef struct _snd_intel8x0 intel8x0_t;
@@ -424,6 +425,7 @@ struct _snd_intel8x0 {
unsigned xbox: 1; /* workaround for Xbox AC'97 detection */
int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */
+ unsigned int sdm_saved; /* SDM reg value */
ac97_bus_t *ac97_bus;
ac97_t *ac97[3];
@@ -861,12 +863,16 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
unsigned long port = ichdev->reg_offset;
switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
+ ichdev->suspended = 0;
+ /* fallthru */
+ case SNDRV_PCM_TRIGGER_START:
val = ICH_IOCE | ICH_STARTBM;
break;
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
+ ichdev->suspended = 1;
+ /* fallthru */
+ case SNDRV_PCM_TRIGGER_STOP:
val = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -898,9 +904,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
val = igetdword(chip, ICHREG(ALI_DMACR));
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ichdev->suspended = 0;
+ /* fallthru */
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/* clear FIFO for synchronization of channels */
fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
@@ -912,9 +920,11 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ichdev->suspended = 1;
+ /* fallthru */
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
iputbyte(chip, port + ICH_REG_OFF_CR, 0);
while (igetbyte(chip, port + ICH_REG_OFF_CR))
@@ -993,6 +1003,8 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
{
unsigned int cnt;
int dbl = runtime->rate > 48000;
+
+ spin_lock_irq(&chip->reg_lock);
switch (chip->device_type) {
case DEVICE_ALI:
cnt = igetdword(chip, ICHREG(ALI_SCR));
@@ -1036,6 +1048,7 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
iputdword(chip, ICHREG(GLOB_CNT), cnt);
break;
}
+ spin_unlock_irq(&chip->reg_lock);
}
static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@@ -1047,15 +1060,12 @@ static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
ichdev->physbuf = runtime->dma_addr;
ichdev->size = snd_pcm_lib_buffer_bytes(substream);
ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
- spin_lock_irq(&chip->reg_lock);
if (ichdev->ichd == ICHD_PCMOUT) {
snd_intel8x0_setup_pcm_out(chip, runtime);
- if (chip->device_type == DEVICE_INTEL_ICH4) {
+ if (chip->device_type == DEVICE_INTEL_ICH4)
ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
- }
}
snd_intel8x0_setup_periods(chip, ichdev);
- spin_unlock_irq(&chip->reg_lock);
return 0;
}
@@ -1816,6 +1826,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x103c,
+ .subdevice = 0x0934,
+ .name = "HP nx8220",
+ .type = AC97_TUNE_MUTE_LED
+ },
+ {
+ .subvendor = 0x103c,
+ .subdevice = 0x099c,
+ .name = "HP nx6110", /* AD1981B */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x103c,
.subdevice = 0x129d,
.name = "HP xw8000",
.type = AC97_TUNE_HP_ONLY
@@ -1869,6 +1891,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
.type = AC97_TUNE_HP_ONLY
},
{
+ .subvendor = 0x10cf,
+ .subdevice = 0x12ec,
+ .name = "Fujitsu-Siemens 4010",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
.subvendor = 0x10f1,
.subdevice = 0x2665,
.name = "Fujitsu-Siemens Celsius", /* AD1981? */
@@ -2373,6 +2401,11 @@ static int intel8x0_suspend(snd_card_t *card, pm_message_t state)
for (i = 0; i < 3; i++)
if (chip->ac97[i])
snd_ac97_suspend(chip->ac97[i]);
+ if (chip->device_type == DEVICE_INTEL_ICH4)
+ chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
+
+ if (chip->irq >= 0)
+ free_irq(chip->irq, (void *)chip);
pci_disable_device(chip->pci);
return 0;
}
@@ -2384,7 +2417,19 @@ static int intel8x0_resume(snd_card_t *card)
pci_enable_device(chip->pci);
pci_set_master(chip->pci);
- snd_intel8x0_chip_init(chip, 0);
+ request_irq(chip->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip);
+ synchronize_irq(chip->irq);
+ snd_intel8x0_chip_init(chip, 1);
+
+ /* re-initialize mixer stuff */
+ if (chip->device_type == DEVICE_INTEL_ICH4) {
+ /* enable separate SDINs for ICH4 */
+ iputbyte(chip, ICHREG(SDM), chip->sdm_saved);
+ /* use slot 10/11 for SPDIF */
+ iputdword(chip, ICHREG(GLOB_CNT),
+ (igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK) |
+ ICH_PCM_SPDIF_1011);
+ }
/* refill nocache */
if (chip->fix_nocache)
@@ -2406,6 +2451,20 @@ static int intel8x0_resume(snd_card_t *card)
}
}
+ /* resume status */
+ for (i = 0; i < chip->bdbars_count; i++) {
+ ichdev_t *ichdev = &chip->ichd[i];
+ unsigned long port = ichdev->reg_offset;
+ if (! ichdev->substream || ! ichdev->suspended)
+ continue;
+ if (ichdev->ichd == ICHD_PCMOUT)
+ snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime);
+ iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
+ iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+ iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ);
+ iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+ }
+
return 0;
}
#endif /* CONFIG_PM */
@@ -2451,8 +2510,7 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
}
do_gettimeofday(&start_time);
spin_unlock_irq(&chip->reg_lock);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20);
+ msleep(50);
spin_lock_irq(&chip->reg_lock);
/* check the position */
pos = ichdev->fragsize1;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 79d8eda54f0d..d2aa9c82d41e 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2067,7 +2067,7 @@ static int snd_korg1212_control_sync_put(snd_kcontrol_t * kcontrol, snd_ctl_elem
}, \
{ \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, \
- .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = c_name " Monitor Phase Invert", \
.info = snd_korg1212_control_phase_info, \
.get = snd_korg1212_control_phase_get, \
@@ -2082,7 +2082,7 @@ static snd_kcontrol_new_t snd_korg1212_controls[] = {
MON_MIXER(4, "ADAT-5"), MON_MIXER(5, "ADAT-6"), MON_MIXER(6, "ADAT-7"), MON_MIXER(7, "ADAT-8"),
{
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE,
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Sync Source",
.info = snd_korg1212_control_sync_info,
.get = snd_korg1212_control_sync_get,
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 096f15132853..39b5e7db1543 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1050,27 +1050,22 @@ static struct m3_hv_quirk m3_hv_quirk_list[] = {
* lowlevel functions
*/
-#define big_mdelay(msec) do {\
- set_current_state(TASK_UNINTERRUPTIBLE);\
- schedule_timeout(((msec) * HZ) / 1000);\
-} while (0)
-
-inline static void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg)
+static inline void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg)
{
outw(value, chip->iobase + reg);
}
-inline static u16 snd_m3_inw(m3_t *chip, unsigned long reg)
+static inline u16 snd_m3_inw(m3_t *chip, unsigned long reg)
{
return inw(chip->iobase + reg);
}
-inline static void snd_m3_outb(m3_t *chip, u8 value, unsigned long reg)
+static inline void snd_m3_outb(m3_t *chip, u8 value, unsigned long reg)
{
outb(value, chip->iobase + reg);
}
-inline static u8 snd_m3_inb(m3_t *chip, unsigned long reg)
+static inline u8 snd_m3_inb(m3_t *chip, unsigned long reg)
{
return inb(chip->iobase + reg);
}
@@ -1096,7 +1091,7 @@ static void snd_m3_assp_write(m3_t *chip, u16 region, u16 index, u16 data)
static void snd_m3_assp_halt(m3_t *chip)
{
chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
- big_mdelay(10);
+ msleep(10);
snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
}
@@ -2108,9 +2103,9 @@ static void snd_m3_ac97_reset(m3_t *chip)
*/
tmp = inw(io + RING_BUS_CTRL_A);
outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
- big_mdelay(20);
+ msleep(20);
outw(tmp, io + RING_BUS_CTRL_A);
- big_mdelay(50);
+ msleep(50);
#endif
}
@@ -2525,9 +2520,13 @@ static void
snd_m3_enable_ints(m3_t *chip)
{
unsigned long io = chip->iobase;
+ unsigned short val;
/* TODO: MPU401 not supported yet */
- outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
+ val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
+ if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+ val |= HV_INT_ENABLE;
+ outw(val, io + HOST_INT_CTRL);
outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
io + ASSP_CONTROL_C);
}
@@ -2589,7 +2588,7 @@ static int m3_suspend(snd_card_t *card, pm_message_t state)
snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97);
- big_mdelay(10); /* give the assp a chance to idle.. */
+ msleep(10); /* give the assp a chance to idle.. */
snd_m3_assp_halt(chip);
@@ -2697,6 +2696,8 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
}
spin_lock_init(&chip->reg_lock);
+ spin_lock_init(&chip->ac97_lock);
+
switch (pci->device) {
case PCI_DEVICE_ID_ESS_ALLEGRO:
case PCI_DEVICE_ID_ESS_ALLEGRO_1:
@@ -2765,6 +2766,8 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
snd_m3_assp_init(chip);
snd_m3_amp_enable(chip, 1);
+ tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+
if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ,
card->driver, (void *)chip)) {
snd_printk("unable to grab IRQ %d\n", pci->irq);
@@ -2786,9 +2789,6 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
return err;
}
- spin_lock_init(&chip->ac97_lock);
- tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
-
if ((err = snd_m3_mixer(chip)) < 0)
return err;
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 082c0d0f73d2..6c868d913634 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -445,9 +445,9 @@ static int snd_mixart_trigger(snd_pcm_substream_t *subs, int cmd)
static int mixart_sync_nonblock_events(mixart_mgr_t *mgr)
{
- int timeout = HZ;
+ unsigned long timeout = jiffies + HZ;
while (atomic_read(&mgr->msg_processed) > 0) {
- if (! timeout--) {
+ if (time_after(jiffies, timeout)) {
snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
return -EBUSY;
}
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 8a52091f8552..2bbeb10ff7c4 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -189,6 +189,7 @@ struct snd_nm256_stream {
nm256_t *chip;
snd_pcm_substream_t *substream;
int running;
+ int suspended;
u32 buf; /* offset from chip->buffer */
int bufsize; /* buffer size in bytes */
@@ -231,8 +232,10 @@ struct snd_nm256 {
int mixer_status_mask; /* bit mask to test the mixer status */
int irq;
+ int irq_acks;
irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
int badintrcount; /* counter to check bogus interrupts */
+ struct semaphore irq_mutex;
nm256_stream_t streams[2];
@@ -285,43 +288,43 @@ MODULE_DEVICE_TABLE(pci, snd_nm256_ids);
* lowlvel stuffs
*/
-inline static u8
+static inline u8
snd_nm256_readb(nm256_t *chip, int offset)
{
return readb(chip->cport + offset);
}
-inline static u16
+static inline u16
snd_nm256_readw(nm256_t *chip, int offset)
{
return readw(chip->cport + offset);
}
-inline static u32
+static inline u32
snd_nm256_readl(nm256_t *chip, int offset)
{
return readl(chip->cport + offset);
}
-inline static void
+static inline void
snd_nm256_writeb(nm256_t *chip, int offset, u8 val)
{
writeb(val, chip->cport + offset);
}
-inline static void
+static inline void
snd_nm256_writew(nm256_t *chip, int offset, u16 val)
{
writew(val, chip->cport + offset);
}
-inline static void
+static inline void
snd_nm256_writel(nm256_t *chip, int offset, u32 val)
{
writel(val, chip->cport + offset);
}
-inline static void
+static inline void
snd_nm256_write_buffer(nm256_t *chip, void *src, int offset, int size)
{
offset -= chip->buffer_start;
@@ -464,6 +467,37 @@ snd_nm256_set_format(nm256_t *chip, nm256_stream_t *s, snd_pcm_substream_t *subs
}
}
+/* acquire interrupt */
+static int snd_nm256_acquire_irq(nm256_t *chip)
+{
+ down(&chip->irq_mutex);
+ if (chip->irq < 0) {
+ if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
+ chip->card->driver, (void*)chip)) {
+ snd_printk("unable to grab IRQ %d\n", chip->pci->irq);
+ up(&chip->irq_mutex);
+ return -EBUSY;
+ }
+ chip->irq = chip->pci->irq;
+ }
+ chip->irq_acks++;
+ up(&chip->irq_mutex);
+ return 0;
+}
+
+/* release interrupt */
+static void snd_nm256_release_irq(nm256_t *chip)
+{
+ down(&chip->irq_mutex);
+ if (chip->irq_acks > 0)
+ chip->irq_acks--;
+ if (chip->irq_acks == 0 && chip->irq >= 0) {
+ free_irq(chip->irq, (void*)chip);
+ chip->irq = -1;
+ }
+ up(&chip->irq_mutex);
+}
+
/*
* start / stop
*/
@@ -538,15 +572,19 @@ snd_nm256_playback_trigger(snd_pcm_substream_t *substream, int cmd)
spin_lock(&chip->reg_lock);
switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
+ s->suspended = 0;
+ /* fallthru */
+ case SNDRV_PCM_TRIGGER_START:
if (! s->running) {
snd_nm256_playback_start(chip, s, substream);
s->running = 1;
}
break;
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
+ s->suspended = 1;
+ /* fallthru */
+ case SNDRV_PCM_TRIGGER_STOP:
if (s->running) {
snd_nm256_playback_stop(chip);
s->running = 0;
@@ -818,6 +856,8 @@ snd_nm256_playback_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
+ if (snd_nm256_acquire_irq(chip) < 0)
+ return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK],
substream, &snd_nm256_playback);
return 0;
@@ -828,6 +868,8 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
{
nm256_t *chip = snd_pcm_substream_chip(substream);
+ if (snd_nm256_acquire_irq(chip) < 0)
+ return -EBUSY;
snd_nm256_setup_stream(chip, &chip->streams[SNDRV_PCM_STREAM_CAPTURE],
substream, &snd_nm256_capture);
return 0;
@@ -839,6 +881,9 @@ snd_nm256_capture_open(snd_pcm_substream_t *substream)
static int
snd_nm256_playback_close(snd_pcm_substream_t *substream)
{
+ nm256_t *chip = snd_pcm_substream_chip(substream);
+
+ snd_nm256_release_irq(chip);
return 0;
}
@@ -846,6 +891,9 @@ snd_nm256_playback_close(snd_pcm_substream_t *substream)
static int
snd_nm256_capture_close(snd_pcm_substream_t *substream)
{
+ nm256_t *chip = snd_pcm_substream_chip(substream);
+
+ snd_nm256_release_irq(chip);
return 0;
}
@@ -915,18 +963,16 @@ snd_nm256_pcm(nm256_t *chip, int device)
static void
snd_nm256_init_chip(nm256_t *chip)
{
- spin_lock_irq(&chip->reg_lock);
/* Reset everything. */
snd_nm256_writeb(chip, 0x0, 0x11);
snd_nm256_writew(chip, 0x214, 0);
/* stop sounds.. */
//snd_nm256_playback_stop(chip);
//snd_nm256_capture_stop(chip);
- spin_unlock_irq(&chip->reg_lock);
}
-inline static void
+static irqreturn_t
snd_nm256_intr_check(nm256_t *chip)
{
if (chip->badintrcount++ > 1000) {
@@ -947,7 +993,9 @@ snd_nm256_intr_check(nm256_t *chip)
if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
snd_nm256_capture_stop(chip);
chip->badintrcount = 0;
+ return IRQ_HANDLED;
}
+ return IRQ_NONE;
}
/*
@@ -969,10 +1017,8 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readw(chip, NM_INT_REG);
/* Not ours. */
- if (status == 0) {
- snd_nm256_intr_check(chip);
- return IRQ_NONE;
- }
+ if (status == 0)
+ return snd_nm256_intr_check(chip);
chip->badintrcount = 0;
@@ -1036,10 +1082,8 @@ snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
status = snd_nm256_readl(chip, NM_INT_REG);
/* Not ours. */
- if (status == 0) {
- snd_nm256_intr_check(chip);
- return IRQ_NONE;
- }
+ if (status == 0)
+ return snd_nm256_intr_check(chip);
chip->badintrcount = 0;
@@ -1192,7 +1236,7 @@ snd_nm256_mixer(nm256_t *chip)
AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
- AC97_EXTENDED_ID,
+ /*AC97_EXTENDED_ID,*/
AC97_VENDOR_ID1, AC97_VENDOR_ID2,
-1
};
@@ -1206,6 +1250,7 @@ snd_nm256_mixer(nm256_t *chip)
for (i = 0; mixer_regs[i] >= 0; i++)
set_bit(mixer_regs[i], ac97.reg_accessed);
ac97.private_data = chip;
+ pbus->no_vra = 1;
err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
if (err < 0)
return err;
@@ -1281,6 +1326,7 @@ static int nm256_suspend(snd_card_t *card, pm_message_t state)
static int nm256_resume(snd_card_t *card)
{
nm256_t *chip = card->pm_private_data;
+ int i;
/* Perform a full reset on the hardware */
pci_enable_device(chip->pci);
@@ -1289,6 +1335,15 @@ static int nm256_resume(snd_card_t *card)
/* restore ac97 */
snd_ac97_resume(chip->ac97);
+ for (i = 0; i < 2; i++) {
+ nm256_stream_t *s = &chip->streams[i];
+ if (s->substream && s->suspended) {
+ spin_lock_irq(&chip->reg_lock);
+ snd_nm256_set_format(chip, s, s->substream);
+ spin_unlock_irq(&chip->reg_lock);
+ }
+ }
+
return 0;
}
#endif /* CONFIG_PM */
@@ -1360,6 +1415,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->use_cache = usecache;
spin_lock_init(&chip->reg_lock);
chip->irq = -1;
+ init_MUTEX(&chip->irq_mutex);
chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize;
chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize;
@@ -1470,15 +1526,6 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
}
- /* acquire interrupt */
- if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
- card->driver, (void*)chip)) {
- err = -EBUSY;
- snd_printk("unable to grab IRQ %d\n", pci->irq);
- goto __error;
- }
- chip->irq = pci->irq;
-
/* Fixed setting. */
chip->mixer_base = NM_MIXER_OFFSET;
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index b7b554df6705..456be39e8e4a 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1900,7 +1900,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
.info = snd_rme32_control_spdif_mask_info,
.get = snd_rme32_control_spdif_mask_get,
@@ -1908,7 +1908,7 @@ static snd_kcontrol_new_t snd_rme32_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK),
.info = snd_rme32_control_spdif_mask_info,
.get = snd_rme32_control_spdif_mask_get,
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 10c4f45a913c..9645e9004a48 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2266,7 +2266,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_rme96_control_spdif_mask_info,
.get = snd_rme96_control_spdif_mask_get,
@@ -2276,7 +2276,7 @@ static snd_kcontrol_new_t snd_rme96_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_rme96_control_spdif_mask_info,
.get = snd_rme96_control_spdif_mask_get,
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index a673cc438b91..6694866089b5 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -445,6 +445,7 @@ struct _hdsp {
u32 control2_register; /* cached value */
u32 creg_spdif;
u32 creg_spdif_stream;
+ int clock_source_locked;
char *card_name; /* digiface/multiface */
HDSP_IO_Type io_type; /* ditto, but for code use */
unsigned short firmware_rev;
@@ -678,8 +679,7 @@ static int snd_hdsp_load_firmware_from_cache(hdsp_t *hdsp) {
}
if ((1000 / HZ) < 3000) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((3000 * HZ + 999) / 1000);
+ ssleep(3);
} else {
mdelay(3000);
}
@@ -1524,7 +1524,7 @@ static int snd_hdsp_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_spdif_in, \
@@ -1584,7 +1584,7 @@ static int snd_hdsp_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out }
@@ -1638,7 +1638,7 @@ static int snd_hdsp_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
}
#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional }
@@ -1683,7 +1683,7 @@ static int snd_hdsp_put_spdif_professional(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_SPDIF_EMPHASIS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis }
@@ -1728,7 +1728,7 @@ static int snd_hdsp_put_spdif_emphasis(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
}
#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_hdsp_info_spdif_bits, \
.get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio }
@@ -1773,7 +1773,7 @@ static int snd_hdsp_put_spdif_nonaudio(snd_kcontrol_t * kcontrol, snd_ctl_elem_v
}
#define HDSP_SPDIF_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1834,7 +1834,7 @@ static int snd_hdsp_get_spdif_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_ele
}
#define HDSP_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1858,7 +1858,7 @@ static int snd_hdsp_get_system_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_el
}
#define HDSP_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1918,7 +1918,7 @@ static int snd_hdsp_get_autosync_sample_rate(snd_kcontrol_t * kcontrol, snd_ctl_
}
#define HDSP_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1958,7 +1958,7 @@ static int snd_hdsp_get_system_clock_mode(snd_kcontrol_t * kcontrol, snd_ctl_ele
}
#define HDSP_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_clock_source, \
@@ -2095,8 +2095,36 @@ static int snd_hdsp_put_clock_source(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
return change;
}
+static int snd_hdsp_info_clock_source_lock(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_hdsp_get_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
+ return 0;
+}
+
+static int snd_hdsp_put_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+ hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+ int change;
+
+ change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
+ if (change)
+ hdsp->clock_source_locked = ucontrol->value.integer.value[0];
+ return change;
+}
+
#define HDSP_DA_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_da_gain, \
@@ -2182,7 +2210,7 @@ static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_AD_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_ad_gain, \
@@ -2268,7 +2296,7 @@ static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_PHONE_GAIN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_phone_gain, \
@@ -2354,7 +2382,7 @@ static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value
}
#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_xlr_breakout_cable, \
@@ -2419,7 +2447,7 @@ static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_el
Switching this on desactivates external ADAT
*/
#define HDSP_AEB(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_aeb, \
@@ -2480,7 +2508,7 @@ static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * uc
}
#define HDSP_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_pref_sync_ref, \
@@ -2613,7 +2641,7 @@ static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define HDSP_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -2669,7 +2697,7 @@ static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define HDSP_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_line_out, \
@@ -2729,7 +2757,7 @@ static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define HDSP_PRECISE_POINTER(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_precise_pointer, \
@@ -2783,7 +2811,7 @@ static int snd_hdsp_put_precise_pointer(snd_kcontrol_t * kcontrol, snd_ctl_elem_
}
#define HDSP_USE_MIDI_TASKLET(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
.name = xname, \
.index = xindex, \
.info = snd_hdsp_info_use_midi_tasklet, \
@@ -2840,6 +2868,7 @@ static int snd_hdsp_put_use_midi_tasklet(snd_kcontrol_t * kcontrol, snd_ctl_elem
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
.name = xname, \
.index = xindex, \
+ .device = 0, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdsp_info_mixer, \
@@ -2911,7 +2940,7 @@ static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *
}
#define HDSP_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2955,7 +2984,7 @@ static int snd_hdsp_get_wc_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define HDSP_SPDIF_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2987,7 +3016,7 @@ static int snd_hdsp_get_spdif_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_elem
}
#define HDSP_ADATSYNC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -3018,7 +3047,7 @@ static int snd_hdsp_get_adatsync_sync_check(snd_kcontrol_t * kcontrol, snd_ctl_e
}
#define HDSP_ADAT_SYNC_CHECK \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdsp_info_sync_check, \
.get = snd_hdsp_get_adat_sync_check \
@@ -3091,7 +3120,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_hdsp_control_spdif_mask_info,
.get = snd_hdsp_control_spdif_mask_get,
@@ -3101,7 +3130,7 @@ static snd_kcontrol_new_t snd_hdsp_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_hdsp_control_spdif_mask_info,
.get = snd_hdsp_control_spdif_mask_get,
@@ -3117,6 +3146,13 @@ HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0),
HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
/* 'Sample Clock Source' complies with the alsa control naming scheme */
HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sample Clock Source Locking",
+ .info = snd_hdsp_info_clock_source_lock,
+ .get = snd_hdsp_get_clock_source_lock,
+ .put = snd_hdsp_put_clock_source_lock,
+},
HDSP_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
HDSP_PREF_SYNC_REF("Preferred Sync Reference", 0),
HDSP_AUTOSYNC_REF("AutoSync Reference", 0),
@@ -3349,6 +3385,7 @@ snd_hdsp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
+ snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
snd_iprintf(buffer, "\n");
@@ -3853,13 +3890,14 @@ static int snd_hdsp_hw_params(snd_pcm_substream_t *substream,
*/
spin_lock_irq(&hdsp->lock);
- if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
- spin_unlock_irq(&hdsp->lock);
- _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
- return err;
- } else {
- spin_unlock_irq(&hdsp->lock);
+ if (! hdsp->clock_source_locked) {
+ if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
+ spin_unlock_irq(&hdsp->lock);
+ _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
+ return err;
+ }
}
+ spin_unlock_irq(&hdsp->lock);
if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) {
_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
@@ -4284,13 +4322,17 @@ static int snd_hdsp_playback_open(snd_pcm_substream_t *substream)
snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
- if (hdsp->io_type == H9632) {
- runtime->hw.channels_min = hdsp->qs_out_channels;
- runtime->hw.channels_max = hdsp->ss_out_channels;
+ if (hdsp->clock_source_locked) {
+ runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
+ } else if (hdsp->io_type == H9632) {
runtime->hw.rate_max = 192000;
runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
}
+ if (hdsp->io_type == H9632) {
+ runtime->hw.channels_min = hdsp->qs_out_channels;
+ runtime->hw.channels_max = hdsp->ss_out_channels;
+ }
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
snd_hdsp_hw_rule_out_channels, hdsp,
@@ -5036,8 +5078,7 @@ static int __devinit snd_hdsp_create(snd_card_t *card,
if (!is_9652 && !is_9632) {
/* we wait 2 seconds to let freshly inserted cardbus cards do their hardware init */
if ((1000 / HZ) < 2000) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((2000 * HZ + 999) / 1000);
+ ssleep(2);
} else {
mdelay(2000);
}
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 9e86d0eb41ce..5d786d113b25 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -65,7 +65,7 @@ module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable/disable specific HDSPM soundcards.");
module_param_array(precise_ptr, bool, NULL, 0444);
-MODULE_PARM_DESC(precise_ptr, "Enable precise pointer, or disable.");
+MODULE_PARM_DESC(precise_ptr, "Enable or disable precise pointer.");
module_param_array(line_outs_monitor, bool, NULL, 0444);
MODULE_PARM_DESC(line_outs_monitor,
@@ -1104,14 +1104,14 @@ static int snd_hdspm_midi_output_close(snd_rawmidi_substream_t * substream)
return 0;
}
-snd_rawmidi_ops_t snd_hdspm_midi_output =
+static snd_rawmidi_ops_t snd_hdspm_midi_output =
{
.open = snd_hdspm_midi_output_open,
.close = snd_hdspm_midi_output_close,
.trigger = snd_hdspm_midi_output_trigger,
};
-snd_rawmidi_ops_t snd_hdspm_midi_input =
+static snd_rawmidi_ops_t snd_hdspm_midi_input =
{
.open = snd_hdspm_midi_input_open,
.close = snd_hdspm_midi_input_close,
@@ -1168,7 +1168,7 @@ static void hdspm_midi_tasklet(unsigned long arg)
/* get the system sample rate which is set */
#define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1195,7 +1195,7 @@ static int snd_hdspm_get_system_sample_rate(snd_kcontrol_t * kcontrol,
}
#define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1264,7 +1264,7 @@ static int snd_hdspm_get_autosync_sample_rate(snd_kcontrol_t * kcontrol,
}
#define HDSPM_SYSTEM_CLOCK_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1310,7 +1310,7 @@ static int snd_hdspm_get_system_clock_mode(snd_kcontrol_t * kcontrol,
}
#define HDSPM_CLOCK_SOURCE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_clock_source, \
@@ -1457,7 +1457,7 @@ static int snd_hdspm_put_clock_source(snd_kcontrol_t * kcontrol,
}
#define HDSPM_PREF_SYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_pref_sync_ref, \
@@ -1547,7 +1547,7 @@ static int snd_hdspm_put_pref_sync_ref(snd_kcontrol_t * kcontrol,
}
#define HDSPM_AUTOSYNC_REF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ, \
@@ -1604,7 +1604,7 @@ static int snd_hdspm_get_autosync_ref(snd_kcontrol_t * kcontrol,
}
#define HDSPM_LINE_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_line_out, \
@@ -1668,7 +1668,7 @@ static int snd_hdspm_put_line_out(snd_kcontrol_t * kcontrol,
}
#define HDSPM_TX_64(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_tx_64, \
@@ -1731,7 +1731,7 @@ static int snd_hdspm_put_tx_64(snd_kcontrol_t * kcontrol,
}
#define HDSPM_C_TMS(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_c_tms, \
@@ -1794,7 +1794,7 @@ static int snd_hdspm_put_c_tms(snd_kcontrol_t * kcontrol,
}
#define HDSPM_SAFE_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_safe_mode, \
@@ -1857,7 +1857,7 @@ static int snd_hdspm_put_safe_mode(snd_kcontrol_t * kcontrol,
}
#define HDSPM_INPUT_SELECT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.info = snd_hdspm_info_input_select, \
@@ -1941,6 +1941,7 @@ static int snd_hdspm_put_input_select(snd_kcontrol_t * kcontrol,
{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
.name = xname, \
.index = xindex, \
+ .device = 0, \
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_hdspm_info_mixer, \
@@ -2124,7 +2125,7 @@ static int snd_hdspm_put_playback_mixer(snd_kcontrol_t * kcontrol,
}
#define HDSPM_WC_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
@@ -2170,7 +2171,7 @@ static int snd_hdspm_get_wc_sync_check(snd_kcontrol_t * kcontrol,
#define HDSPM_MADI_SYNC_CHECK(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
.index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index f3037402d58f..8ee4d6fd6ea7 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -893,7 +893,7 @@ static int snd_rme9652_control_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl
}
#define RME9652_ADAT1_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_adat1_in, \
.get = snd_rme9652_get_adat1_in, \
.put = snd_rme9652_put_adat1_in }
@@ -971,7 +971,7 @@ static int snd_rme9652_put_adat1_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
#define RME9652_SPDIF_IN(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_in, \
.get = snd_rme9652_get_spdif_in, .put = snd_rme9652_put_spdif_in }
@@ -1042,7 +1042,7 @@ static int snd_rme9652_put_spdif_in(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
}
#define RME9652_SPDIF_OUT(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_spdif_out, \
.get = snd_rme9652_get_spdif_out, .put = snd_rme9652_put_spdif_out }
@@ -1110,7 +1110,7 @@ static int snd_rme9652_put_spdif_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_SYNC_MODE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_mode, \
.get = snd_rme9652_get_sync_mode, .put = snd_rme9652_put_sync_mode }
@@ -1195,7 +1195,7 @@ static int snd_rme9652_put_sync_mode(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_SYNC_PREF(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_sync_pref, \
.get = snd_rme9652_get_sync_pref, .put = snd_rme9652_put_sync_pref }
@@ -1340,7 +1340,7 @@ static int snd_rme9652_put_thru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t
}
#define RME9652_PASSTHRU(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_rme9652_info_passthru, \
.put = snd_rme9652_put_passthru, \
.get = snd_rme9652_get_passthru }
@@ -1386,7 +1386,7 @@ static int snd_rme9652_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
/* Read-only switches */
#define RME9652_SPDIF_RATE(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_spdif_rate, \
.get = snd_rme9652_get_spdif_rate }
@@ -1411,7 +1411,7 @@ static int snd_rme9652_get_spdif_rate(snd_kcontrol_t * kcontrol, snd_ctl_elem_va
}
#define RME9652_ADAT_SYNC(xname, xindex, xidx) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_adat_sync, \
.get = snd_rme9652_get_adat_sync, .private_value = xidx }
@@ -1447,7 +1447,7 @@ static int snd_rme9652_get_adat_sync(snd_kcontrol_t * kcontrol, snd_ctl_elem_val
}
#define RME9652_TC_VALID(xname, xindex) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.info = snd_rme9652_info_tc_valid, \
.get = snd_rme9652_get_tc_valid }
@@ -1470,7 +1470,7 @@ static int snd_rme9652_get_tc_valid(snd_kcontrol_t * kcontrol, snd_ctl_elem_valu
return 0;
}
-#if ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE
+#ifdef ALSA_HAS_STANDARD_WAY_OF_RETURNING_TIMECODE
/* FIXME: this routine needs a port to the new control API --jk */
@@ -1545,7 +1545,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
@@ -1555,7 +1555,7 @@ static snd_kcontrol_new_t snd_rme9652_controls[] = {
},
{
.access = SNDRV_CTL_ELEM_ACCESS_READ,
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
.info = snd_rme9652_control_spdif_mask_info,
.get = snd_rme9652_control_spdif_mask_get,
@@ -1568,7 +1568,7 @@ RME9652_SPDIF_OUT("IEC958 Output also on ADAT1", 0),
RME9652_SYNC_MODE("Sync Mode", 0),
RME9652_SYNC_PREF("Preferred Sync Source", 0),
{
- .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Channels Thru",
.index = 0,
.info = snd_rme9652_info_thru,
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index ccd5ca2ba16f..f30d9d947862 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -472,6 +472,7 @@ void snd_trident_write_voice_regs(trident_t * trident,
break;
default:
snd_BUG();
+ return;
}
outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
@@ -1688,7 +1689,7 @@ static snd_pcm_hardware_t snd_trident_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1713,7 +1714,7 @@ static snd_pcm_hardware_t snd_trident_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
@@ -1738,7 +1739,7 @@ static snd_pcm_hardware_t snd_trident_foldback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@@ -1762,7 +1763,7 @@ static snd_pcm_hardware_t snd_trident_spdif =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
SNDRV_PCM_RATE_48000),
@@ -1783,7 +1784,7 @@ static snd_pcm_hardware_t snd_trident_spdif_7018 =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |
- SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+ SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
@@ -3152,8 +3153,7 @@ static int snd_trident_gameport_open(struct gameport *gameport, int mode)
switch (mode) {
case GAMEPORT_MODE_COOKED:
outb(GAMEPORT_MODE_ADC, TRID_REG(chip, GAMEPORT_GCR));
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1 + 20 * HZ / 1000); /* 20msec */
+ msleep(20);
return 0;
case GAMEPORT_MODE_RAW:
outb(0, TRID_REG(chip, GAMEPORT_GCR));
@@ -3204,7 +3204,7 @@ static inline void snd_trident_free_gameport(trident_t *chip) { }
/*
* delay for 1 tick
*/
-inline static void do_delay(trident_t *chip)
+static inline void do_delay(trident_t *chip)
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index 6cc282681e09..333d3790692a 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -118,7 +118,7 @@ static inline void set_silent_tlb(trident_t *trident, int page)
#endif /* PAGE_SIZE */
/* calculate buffer pointer from offset address */
-inline static void *offset_ptr(trident_t *trident, int offset)
+static inline void *offset_ptr(trident_t *trident, int offset)
{
char *ptr;
ptr = page_to_ptr(trident, get_aligned_page(offset));
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 42c48f0ce8e8..56c6e52d7264 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -547,8 +547,7 @@ static void snd_via82xx_codec_wait(ac97_t *ac97)
int err;
err = snd_via82xx_codec_ready(chip, ac97->num);
/* here we need to wait fairly for long time.. */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/2);
+ msleep(500);
}
static void snd_via82xx_codec_write(ac97_t *ac97,
@@ -664,10 +663,12 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
val = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
val |= VIA_REG_CTRL_START;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break;
@@ -930,12 +931,12 @@ static int snd_via8233_playback_prepare(snd_pcm_substream_t *substream)
if ((rate_changed = via_lock_rate(&chip->rates[0], ac97_rate)) < 0)
return rate_changed;
- if (rate_changed) {
+ if (rate_changed)
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
chip->no_vra ? 48000 : runtime->rate);
- snd_ac97_set_rate(chip->ac97, AC97_SPDIF,
- chip->no_vra ? 48000 : runtime->rate);
- }
+ if (chip->spdif_on && viadev->reg_offset == 0x30)
+ snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate);
+
if (runtime->rate == 48000)
rbits = 0xfffff;
else
@@ -1036,7 +1037,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME |
+ /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_48000,
@@ -1485,7 +1486,7 @@ static int snd_via8233_dxs3_spdif_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_val
}
static snd_kcontrol_new_t snd_via8233_dxs3_spdif_control __devinitdata = {
- .name = "IEC958 Output Switch",
+ .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH),
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.info = snd_via8233_dxs3_spdif_info,
.get = snd_via8233_dxs3_spdif_get,
@@ -1847,7 +1848,7 @@ static void __devinit snd_via82xx_proc_init(via82xx_t *chip)
static int snd_via82xx_chip_init(via82xx_t *chip)
{
unsigned int val;
- int max_count;
+ unsigned long end_time;
unsigned char pval;
#if 0 /* broken on K7M? */
@@ -1889,14 +1890,14 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
}
/* wait until codec ready */
- max_count = ((3 * HZ) / 4) + 1;
+ end_time = jiffies + msecs_to_jiffies(750);
do {
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- } while (--max_count > 0);
+ } while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
snd_printk("AC'97 codec is not ready [0x%x]\n", val);
@@ -1905,7 +1906,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
- max_count = ((3 * HZ) / 4) + 1;
+ end_time = jiffies + msecs_to_jiffies(750);
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
@@ -1916,7 +1917,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
- } while (--max_count > 0);
+ } while (time_before(jiffies, end_time));
/* This is ok, the most of motherboards have only one codec */
__ac97_ok2:
@@ -2154,6 +2155,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x1019, .subdevice = 0x0a81, .action = VIA_DXS_NO_VRA }, /* ECS K7VTA3 v8.0 */
{ .subvendor = 0x1019, .subdevice = 0x0a85, .action = VIA_DXS_NO_VRA }, /* ECS L7VMM2 */
{ .subvendor = 0x1025, .subdevice = 0x0033, .action = VIA_DXS_NO_VRA }, /* Acer Inspire 1353LM */
+ { .subvendor = 0x1025, .subdevice = 0x0046, .action = VIA_DXS_SRC }, /* Acer Aspire 1524 WLMi */
{ .subvendor = 0x1043, .subdevice = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
{ .subvendor = 0x1043, .subdevice = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
{ .subvendor = 0x1043, .subdevice = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/
@@ -2169,16 +2171,18 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x1297, .subdevice = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */
{ .subvendor = 0x1458, .subdevice = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */
{ .subvendor = 0x1462, .subdevice = 0x0080, .action = VIA_DXS_SRC }, /* MSI K8T Neo-FIS2R */
+ { .subvendor = 0x1462, .subdevice = 0x0430, .action = VIA_DXS_SRC }, /* MSI 7142 (K8MM-V) */
{ .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */
{ .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */
{ .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */
{ .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */
+ { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */
{ .subvendor = 0x147b, .subdevice = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */
{ .subvendor = 0x147b, .subdevice = 0x1411, .action = VIA_DXS_ENABLE }, /* ABIT VA-20 */
{ .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
{ .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
{ .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
- { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */
+ { .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */
{ .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
{ .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
{ .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
@@ -2187,6 +2191,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci)
{ .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
{ .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
+ { .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC }, /* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */
{ } /* terminator */
};
struct dxs_whitelist *w;
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 5896d289f9ac..5872d438a04a 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -408,8 +408,7 @@ static void snd_via82xx_codec_wait(ac97_t *ac97)
int err;
err = snd_via82xx_codec_ready(chip, ac97->num);
/* here we need to wait fairly for long time.. */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/2);
+ msleep(500);
}
static void snd_via82xx_codec_write(ac97_t *ac97,
@@ -522,6 +521,7 @@ static int snd_via82xx_pcm_trigger(snd_pcm_substream_t * substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
val |= VIA_REG_CTRL_START;
viadev->running = 1;
break;
@@ -698,7 +698,7 @@ static snd_pcm_hardware_t snd_via82xx_hw =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_RESUME |
+ /* SNDRV_PCM_INFO_RESUME | */
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT,
@@ -923,7 +923,7 @@ static void __devinit snd_via82xx_proc_init(via82xx_t *chip)
static int snd_via82xx_chip_init(via82xx_t *chip)
{
unsigned int val;
- int max_count;
+ unsigned long end_time;
unsigned char pval;
pci_read_config_byte(chip->pci, VIA_MC97_CTRL, &pval);
@@ -962,14 +962,14 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
}
/* wait until codec ready */
- max_count = ((3 * HZ) / 4) + 1;
+ end_time = jiffies + msecs_to_jiffies(750);
do {
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- } while (--max_count > 0);
+ } while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
snd_printk("AC'97 codec is not ready [0x%x]\n", val);
@@ -977,7 +977,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
- max_count = ((3 * HZ) / 4) + 1;
+ end_time = jiffies + msecs_to_jiffies(750);
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
@@ -988,7 +988,7 @@ static int snd_via82xx_chip_init(via82xx_t *chip)
}
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
- } while (--max_count > 0);
+ } while (time_before(jiffies, end_time));
/* This is ok, the most of motherboards have only one codec */
__ac97_ok2:
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 683e9799976f..967bd5e6b23c 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -82,7 +82,7 @@ static int vx2_reg_index[VX_REG_MAX] = {
[VX_GPIOC] = 0, /* on the PLX */
};
-inline static unsigned long vx2_reg_addr(vx_core_t *_chip, int reg)
+static inline unsigned long vx2_reg_addr(vx_core_t *_chip, int reg)
{
struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
return chip->port[vx2_reg_index[reg]] + vx2_reg_offset[reg];
@@ -235,7 +235,7 @@ static void vx2_setup_pseudo_dma(vx_core_t *chip, int do_write)
/*
* vx_release_pseudo_dma - disable the pseudo-DMA mode
*/
-inline static void vx2_release_pseudo_dma(vx_core_t *chip)
+static inline void vx2_release_pseudo_dma(vx_core_t *chip)
{
/* HREQ pin disabled. */
vx_outl(chip, ICR, 0);
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 2ae79610ecb5..054836412dc4 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -84,16 +84,16 @@ static inline void snd_ymfpci_writel(ymfpci_t *chip, u32 offset, u32 val)
static int snd_ymfpci_codec_ready(ymfpci_t *chip, int secondary)
{
- signed long end_time;
+ unsigned long end_time;
u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
- end_time = (jiffies + ((3 * HZ) / 4)) + 1;
+ end_time = jiffies + msecs_to_jiffies(750);
do {
if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
return 0;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- } while (end_time - (signed long)jiffies >= 0);
+ } while (time_before(jiffies, end_time));
snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
return -EBUSY;
}
@@ -321,6 +321,26 @@ static void snd_ymfpci_pcm_interrupt(ymfpci_t *chip, ymfpci_voice_t *voice)
snd_pcm_period_elapsed(ypcm->substream);
spin_lock(&chip->reg_lock);
}
+
+ if (unlikely(ypcm->update_pcm_vol)) {
+ unsigned int subs = ypcm->substream->number;
+ unsigned int next_bank = 1 - chip->active_bank;
+ snd_ymfpci_playback_bank_t *bank;
+ u32 volume;
+
+ bank = &voice->bank[next_bank];
+ volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
+ bank->left_gain_end = volume;
+ if (ypcm->output_rear)
+ bank->eff2_gain_end = volume;
+ if (ypcm->voices[1])
+ bank = &ypcm->voices[1]->bank[next_bank];
+ volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15);
+ bank->right_gain_end = volume;
+ if (ypcm->output_rear)
+ bank->eff3_gain_end = volume;
+ ypcm->update_pcm_vol--;
+ }
}
spin_unlock(&chip->reg_lock);
}
@@ -451,87 +471,74 @@ static int snd_ymfpci_pcm_voice_alloc(ymfpci_pcm_t *ypcm, int voices)
return 0;
}
-static void snd_ymfpci_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
- int rate, int w_16, unsigned long addr,
- unsigned int end,
- int output_front, int output_rear)
+static void snd_ymfpci_pcm_init_voice(ymfpci_pcm_t *ypcm, unsigned int voiceidx,
+ snd_pcm_runtime_t *runtime,
+ int has_pcm_volume)
{
+ ymfpci_voice_t *voice = ypcm->voices[voiceidx];
u32 format;
- u32 delta = snd_ymfpci_calc_delta(rate);
- u32 lpfQ = snd_ymfpci_calc_lpfQ(rate);
- u32 lpfK = snd_ymfpci_calc_lpfK(rate);
+ u32 delta = snd_ymfpci_calc_delta(runtime->rate);
+ u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate);
+ u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
snd_ymfpci_playback_bank_t *bank;
unsigned int nbank;
+ u32 vol_left, vol_right;
+ u8 use_left, use_right;
snd_assert(voice != NULL, return);
- format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
+ if (runtime->channels == 1) {
+ use_left = 1;
+ use_right = 1;
+ } else {
+ use_left = (voiceidx & 1) == 0;
+ use_right = !use_left;
+ }
+ if (has_pcm_volume) {
+ vol_left = cpu_to_le32(ypcm->chip->pcm_mixer
+ [ypcm->substream->number].left << 15);
+ vol_right = cpu_to_le32(ypcm->chip->pcm_mixer
+ [ypcm->substream->number].right << 15);
+ } else {
+ vol_left = cpu_to_le32(0x40000000);
+ vol_right = cpu_to_le32(0x40000000);
+ }
+ format = runtime->channels == 2 ? 0x00010000 : 0;
+ if (snd_pcm_format_width(runtime->format) == 8)
+ format |= 0x80000000;
+ if (runtime->channels == 2 && (voiceidx & 1) != 0)
+ format |= 1;
for (nbank = 0; nbank < 2; nbank++) {
bank = &voice->bank[nbank];
+ memset(bank, 0, sizeof(*bank));
bank->format = cpu_to_le32(format);
- bank->loop_default = 0;
- bank->base = cpu_to_le32(addr);
- bank->loop_start = 0;
- bank->loop_end = cpu_to_le32(end);
- bank->loop_frac = 0;
- bank->eg_gain_end = cpu_to_le32(0x40000000);
+ bank->base = cpu_to_le32(runtime->dma_addr);
+ bank->loop_end = cpu_to_le32(ypcm->buffer_size);
bank->lpfQ = cpu_to_le32(lpfQ);
- bank->status = 0;
- bank->num_of_frames = 0;
- bank->loop_count = 0;
- bank->start = 0;
- bank->start_frac = 0;
bank->delta =
bank->delta_end = cpu_to_le32(delta);
bank->lpfK =
bank->lpfK_end = cpu_to_le32(lpfK);
- bank->eg_gain = cpu_to_le32(0x40000000);
- bank->lpfD1 =
- bank->lpfD2 = 0;
-
- bank->left_gain =
- bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end =
- bank->eff1_gain =
- bank->eff2_gain =
- bank->eff3_gain =
- bank->eff1_gain_end =
- bank->eff2_gain_end =
- bank->eff3_gain_end = 0;
-
- if (!stereo) {
- if (output_front) {
- bank->left_gain =
+ bank->eg_gain =
+ bank->eg_gain_end = cpu_to_le32(0x40000000);
+
+ if (ypcm->output_front) {
+ if (use_left) {
+ bank->left_gain =
+ bank->left_gain_end = vol_left;
+ }
+ if (use_right) {
bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end = cpu_to_le32(0x40000000);
+ bank->right_gain_end = vol_right;
}
- if (output_rear) {
+ }
+ if (ypcm->output_rear) {
+ if (use_left) {
bank->eff2_gain =
- bank->eff2_gain_end =
- bank->eff3_gain =
- bank->eff3_gain_end = cpu_to_le32(0x40000000);
- }
- } else {
- if (output_front) {
- if ((voice->number & 1) == 0) {
- bank->left_gain =
- bank->left_gain_end = cpu_to_le32(0x40000000);
- } else {
- bank->format |= cpu_to_le32(1);
- bank->right_gain =
- bank->right_gain_end = cpu_to_le32(0x40000000);
- }
+ bank->eff2_gain_end = vol_left;
}
- if (output_rear) {
- if ((voice->number & 1) == 0) {
- bank->eff3_gain =
- bank->eff3_gain_end = cpu_to_le32(0x40000000);
- } else {
- bank->format |= cpu_to_le32(1);
- bank->eff2_gain =
- bank->eff2_gain_end = cpu_to_le32(0x40000000);
- }
+ if (use_right) {
+ bank->eff3_gain =
+ bank->eff3_gain_end = vol_right;
}
}
}
@@ -613,7 +620,7 @@ static int snd_ymfpci_playback_hw_free(snd_pcm_substream_t * substream)
static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
{
- // ymfpci_t *chip = snd_pcm_substream_chip(substream);
+ ymfpci_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
ymfpci_pcm_t *ypcm = runtime->private_data;
unsigned int nvoice;
@@ -623,14 +630,8 @@ static int snd_ymfpci_playback_prepare(snd_pcm_substream_t * substream)
ypcm->period_pos = 0;
ypcm->last_pos = 0;
for (nvoice = 0; nvoice < runtime->channels; nvoice++)
- snd_ymfpci_pcm_init_voice(ypcm->voices[nvoice],
- runtime->channels == 2,
- runtime->rate,
- snd_pcm_format_width(runtime->format) == 16,
- runtime->dma_addr,
- ypcm->buffer_size,
- ypcm->output_front,
- ypcm->output_rear);
+ snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
+ substream->pcm == chip->pcm);
return 0;
}
@@ -882,6 +883,7 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
ymfpci_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
ymfpci_pcm_t *ypcm;
+ snd_kcontrol_t *kctl;
int err;
if ((err = snd_ymfpci_playback_open_1(substream)) < 0)
@@ -895,6 +897,10 @@ static int snd_ymfpci_playback_open(snd_pcm_substream_t * substream)
chip->rear_opened++;
}
spin_unlock_irq(&chip->reg_lock);
+
+ kctl = chip->pcm_mixer[substream->number].ctl;
+ kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return 0;
}
@@ -987,6 +993,7 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
{
ymfpci_t *chip = snd_pcm_substream_chip(substream);
ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+ snd_kcontrol_t *kctl;
spin_lock_irq(&chip->reg_lock);
if (ypcm->output_rear && chip->rear_opened > 0) {
@@ -994,6 +1001,9 @@ static int snd_ymfpci_playback_close(snd_pcm_substream_t * substream)
ymfpci_close_extension(chip);
}
spin_unlock_irq(&chip->reg_lock);
+ kctl = chip->pcm_mixer[substream->number].ctl;
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return snd_ymfpci_playback_close_1(substream);
}
@@ -1665,6 +1675,66 @@ static snd_kcontrol_new_t snd_ymfpci_rear_shared __devinitdata = {
.private_value = 2,
};
+/*
+ * PCM voice volume
+ */
+
+static int snd_ymfpci_pcm_vol_info(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_info_t *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x8000;
+ return 0;
+}
+
+static int snd_ymfpci_pcm_vol_get(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int subs = kcontrol->id.subdevice;
+
+ ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left;
+ ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right;
+ return 0;
+}
+
+static int snd_ymfpci_pcm_vol_put(snd_kcontrol_t *kcontrol,
+ snd_ctl_elem_value_t *ucontrol)
+{
+ ymfpci_t *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int subs = kcontrol->id.subdevice;
+ snd_pcm_substream_t *substream;
+ unsigned long flags;
+
+ if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left ||
+ ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
+ chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
+ chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
+
+ substream = (snd_pcm_substream_t *)kcontrol->private_value;
+ spin_lock_irqsave(&chip->voice_lock, flags);
+ if (substream->runtime && substream->runtime->private_data) {
+ ymfpci_pcm_t *ypcm = substream->runtime->private_data;
+ ypcm->update_pcm_vol = 2;
+ }
+ spin_unlock_irqrestore(&chip->voice_lock, flags);
+ return 1;
+ }
+ return 0;
+}
+
+static snd_kcontrol_new_t snd_ymfpci_pcm_volume __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "PCM Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+ .info = snd_ymfpci_pcm_vol_info,
+ .get = snd_ymfpci_pcm_vol_get,
+ .put = snd_ymfpci_pcm_vol_put,
+};
+
/*
* Mixer routines
@@ -1686,6 +1756,7 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
{
ac97_template_t ac97;
snd_kcontrol_t *kctl;
+ snd_pcm_substream_t *substream;
unsigned int idx;
int err;
static ac97_bus_ops_t ops = {
@@ -1739,6 +1810,23 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
return err;
}
+ /* per-voice volume */
+ substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ for (idx = 0; idx < 32; ++idx) {
+ kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.device = chip->pcm->device;
+ kctl->id.subdevice = idx;
+ kctl->private_value = (unsigned long)substream;
+ if ((err = snd_ctl_add(chip->card, kctl)) < 0)
+ return err;
+ chip->pcm_mixer[idx].left = 0x8000;
+ chip->pcm_mixer[idx].right = 0x8000;
+ chip->pcm_mixer[idx].ctl = kctl;
+ substream = substream->next;
+ }
+
return 0;
}
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig
index 3611e298834f..5d1b0b762efa 100644
--- a/sound/pcmcia/Kconfig
+++ b/sound/pcmcia/Kconfig
@@ -8,23 +8,12 @@ config SND_VXPOCKET
depends on SND && PCMCIA && ISA
select SND_VX_LIB
help
- Say Y here to include support for Digigram VXpocket
- soundcards.
+ Say Y here to include support for Digigram VXpocket and
+ VXpocket 440 soundcards.
To compile this driver as a module, choose M here: the module
will be called snd-vxpocket.
-config SND_VXP440
- tristate "Digigram VXpocket 440"
- depends on SND && PCMCIA && ISA
- select SND_VX_LIB
- help
- Say Y here to include support for Digigram VXpocket 440
- soundcards.
-
- To compile this driver as a module, choose M here: the module
- will be called snd-vxp440.
-
config SND_PDAUDIOCF
tristate "Sound Core PDAudioCF"
depends on SND && PCMCIA && ISA
diff --git a/sound/pcmcia/vx/Makefile b/sound/pcmcia/vx/Makefile
index f35dfa1af094..54971f01e968 100644
--- a/sound/pcmcia/vx/Makefile
+++ b/sound/pcmcia/vx/Makefile
@@ -3,9 +3,6 @@
# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
#
-snd-vx-cs-objs := vx_entry.o vxp_ops.o vxp_mixer.o
-snd-vxpocket-objs := vxpocket.o
-snd-vxp440-objs := vxp440.o
+snd-vxpocket-objs := vxpocket.o vxp_ops.o vxp_mixer.o
-obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o snd-vx-cs.o
-obj-$(CONFIG_SND_VXP440) += snd-vxp440.o snd-vx-cs.o
+obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
deleted file mode 100644
index df7a39ba9680..000000000000
--- a/sound/pcmcia/vx/vx_entry.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Driver for Digigram VXpocket soundcards
- *
- * PCMCIA entry part
- *
- * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <sound/driver.h>
-#include <sound/core.h>
-#include "vxpocket.h"
-#include <pcmcia/ciscode.h>
-#include <pcmcia/cisreg.h>
-
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("Common routines for Digigram PCMCIA VX drivers");
-MODULE_LICENSE("GPL");
-
-/*
- * prototypes
- */
-static void vxpocket_config(dev_link_t *link);
-
-
-static void vxpocket_release(dev_link_t *link)
-{
- if (link->state & DEV_CONFIG) {
- /* release cs resources */
- pcmcia_release_configuration(link->handle);
- pcmcia_release_io(link->handle, &link->io);
- pcmcia_release_irq(link->handle, &link->irq);
- link->state &= ~DEV_CONFIG;
- }
-}
-
-/*
- * destructor
- */
-static int snd_vxpocket_free(vx_core_t *chip)
-{
- struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
- struct snd_vxp_entry *hw;
- dev_link_t *link = &vxp->link;
-
- vxpocket_release(link);
-
- /* Break the link with Card Services */
- if (link->handle)
- pcmcia_deregister_client(link->handle);
-
- hw = vxp->hw_entry;
- if (hw)
- hw->card_list[vxp->index] = NULL;
- chip->card = NULL;
- kfree(chip->dev);
-
- snd_vx_free_firmware(chip);
- kfree(chip);
- return 0;
-}
-
-static int snd_vxpocket_dev_free(snd_device_t *device)
-{
- vx_core_t *chip = device->device_data;
- return snd_vxpocket_free(chip);
-}
-
-/*
- * snd_vxpocket_attach - attach callback for cs
- * @hw: the hardware information
- */
-dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
-{
- client_reg_t client_reg; /* Register with cardmgr */
- dev_link_t *link; /* Info for cardmgr */
- int i, ret;
- vx_core_t *chip;
- struct snd_vxpocket *vxp;
- snd_card_t *card;
- static snd_device_ops_t ops = {
- .dev_free = snd_vxpocket_dev_free,
- };
-
- snd_printdd(KERN_DEBUG "vxpocket_attach called\n");
- /* find an empty slot from the card list */
- for (i = 0; i < SNDRV_CARDS; i++) {
- if (! hw->card_list[i])
- break;
- }
- if (i >= SNDRV_CARDS) {
- snd_printk(KERN_ERR "vxpocket: too many cards found\n");
- return NULL;
- }
- if (! hw->enable_table[i])
- return NULL; /* disabled explicitly */
-
- /* ok, create a card instance */
- card = snd_card_new(hw->index_table[i], hw->id_table[i], THIS_MODULE, 0);
- if (card == NULL) {
- snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
- return NULL;
- }
-
- chip = snd_vx_create(card, hw->hardware, hw->ops,
- sizeof(struct snd_vxpocket) - sizeof(vx_core_t));
- if (! chip)
- return NULL;
-
-#ifdef SND_VX_FW_LOADER
- /* fake a device here since pcmcia doesn't give a valid device... */
- chip->dev = kcalloc(1, sizeof(*chip->dev), GFP_KERNEL);
- if (! chip->dev) {
- snd_printk(KERN_ERR "vxp: can't malloc chip->dev\n");
- kfree(chip);
- snd_card_free(card);
- return NULL;
- }
- device_initialize(chip->dev);
- sprintf(chip->dev->bus_id, "vxpocket%d", i);
-#endif
-
- if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
- kfree(chip);
- snd_card_free(card);
- return NULL;
- }
-
- vxp = (struct snd_vxpocket *)chip;
- vxp->index = i;
- vxp->hw_entry = hw;
- chip->ibl.size = hw->ibl[i];
- hw->card_list[i] = chip;
-
- link = &vxp->link;
- link->priv = chip;
-
- link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
- link->io.NumPorts1 = 16;
-
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
- // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
-
- link->irq.IRQInfo1 = IRQ_LEVEL_ID;
- link->irq.Handler = &snd_vx_irq_handler;
- link->irq.Instance = chip;
-
- link->conf.Attributes = CONF_ENABLE_IRQ;
- link->conf.Vcc = 50;
- link->conf.IntType = INT_MEMORY_AND_IO;
- link->conf.ConfigIndex = 1;
- link->conf.Present = PRESENT_OPTION;
-
- /* Register with Card Services */
- memset(&client_reg, 0, sizeof(client_reg));
- client_reg.dev_info = hw->dev_info;
- client_reg.Version = 0x0210;
- client_reg.event_callback_args.client_data = link;
-
- ret = pcmcia_register_client(&link->handle, &client_reg);
- if (ret != CS_SUCCESS) {
- cs_error(link->handle, RegisterClient, ret);
- snd_card_free(card);
- return NULL;
- }
-
- /* Chain drivers */
- link->next = hw->dev_list;
- hw->dev_list = link;
-
- /* snd_card_set_pm_callback(card, snd_vxpocket_suspend, snd_vxpocket_resume, chip); */
-
- return link;
-}
-
-
-/**
- * snd_vxpocket_assign_resources - initialize the hardware and card instance.
- * @port: i/o port for the card
- * @irq: irq number for the card
- *
- * this function assigns the specified port and irq, boot the card,
- * create pcm and control instances, and initialize the rest hardware.
- *
- * returns 0 if successful, or a negative error code.
- */
-static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
-{
- int err;
- snd_card_t *card = chip->card;
- struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-
- snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
- vxp->port = port;
-
- sprintf(card->shortname, "Digigram %s", card->driver);
- sprintf(card->longname, "%s at 0x%x, irq %i",
- card->shortname, port, irq);
-
- chip->irq = irq;
-
- if ((err = snd_vx_setup_firmware(chip)) < 0)
- return err;
-
- return 0;
-}
-
-
-/*
- * snd_vxpocket_detach - detach callback for cs
- * @hw: the hardware information
- */
-void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link)
-{
- vx_core_t *chip;
-
- if (! link)
- return;
-
- chip = link->priv;
-
- snd_printdd(KERN_DEBUG "vxpocket_detach called\n");
- /* Remove the interface data from the linked list */
- if (hw) {
- dev_link_t **linkp;
- /* Locate device structure */
- for (linkp = &hw->dev_list; *linkp; linkp = &(*linkp)->next)
- if (*linkp == link) {
- *linkp = link->next;
- break;
- }
- }
- chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
- snd_card_disconnect(chip->card);
- snd_card_free_in_thread(chip->card);
-}
-
-/*
- * configuration callback
- */
-
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
-static void vxpocket_config(dev_link_t *link)
-{
- client_handle_t handle = link->handle;
- vx_core_t *chip = link->priv;
- struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
- tuple_t tuple;
- cisparse_t *parse = NULL;
- u_short buf[32];
- int last_fn, last_ret;
-
- snd_printdd(KERN_DEBUG "vxpocket_config called\n");
- parse = kmalloc(sizeof(*parse), GFP_KERNEL);
- if (! parse) {
- snd_printk(KERN_ERR "vx: cannot allocate\n");
- return;
- }
- tuple.Attributes = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
- tuple.DesiredTuple = CISTPL_CONFIG;
- CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
- CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
- CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
- link->conf.ConfigBase = parse->config.base;
- link->conf.Present = parse->config.rmask[0];
-
- /* Configure card */
- link->state |= DEV_CONFIG;
-
- CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
- CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
- CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
-
- if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
- goto failed;
-
- link->dev = &vxp->node;
- link->state &= ~DEV_CONFIG_PENDING;
- kfree(parse);
- return;
-
-cs_failed:
- cs_error(link->handle, last_fn, last_ret);
-failed:
- pcmcia_release_configuration(link->handle);
- pcmcia_release_io(link->handle, &link->io);
- pcmcia_release_irq(link->handle, &link->irq);
- link->state &= ~DEV_CONFIG;
- kfree(parse);
-}
-
-
-/*
- * event callback
- */
-int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
-{
- dev_link_t *link = args->client_data;
- vx_core_t *chip = link->priv;
-
- switch (event) {
- case CS_EVENT_CARD_REMOVAL:
- snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n");
- link->state &= ~DEV_PRESENT;
- if (link->state & DEV_CONFIG) {
- chip->chip_status |= VX_STAT_IS_STALE;
- }
- break;
- case CS_EVENT_CARD_INSERTION:
- snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
- link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
- vxpocket_config(link);
- break;
-#ifdef CONFIG_PM
- case CS_EVENT_PM_SUSPEND:
- snd_printdd(KERN_DEBUG "SUSPEND\n");
- link->state |= DEV_SUSPEND;
- if (chip && chip->card->pm_suspend) {
- snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
- chip->card->pm_suspend(chip->card, PMSG_SUSPEND);
- }
- /* Fall through... */
- case CS_EVENT_RESET_PHYSICAL:
- snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
- if (link->state & DEV_CONFIG)
- pcmcia_release_configuration(link->handle);
- break;
- case CS_EVENT_PM_RESUME:
- snd_printdd(KERN_DEBUG "RESUME\n");
- link->state &= ~DEV_SUSPEND;
- /* Fall through... */
- case CS_EVENT_CARD_RESET:
- snd_printdd(KERN_DEBUG "CARD_RESET\n");
- if (DEV_OK(link)) {
- //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
- snd_printdd(KERN_DEBUG "requestconfig...\n");
- pcmcia_request_configuration(link->handle, &link->conf);
- if (chip && chip->card->pm_resume) {
- snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
- chip->card->pm_resume(chip->card);
- }
- }
- snd_printdd(KERN_DEBUG "resume done!\n");
- break;
-#endif
- }
- return 0;
-}
-
-/*
- * exported stuffs
- */
-EXPORT_SYMBOL(snd_vxpocket_ops);
-EXPORT_SYMBOL(snd_vxpocket_attach);
-EXPORT_SYMBOL(vxpocket_event);
-EXPORT_SYMBOL(snd_vxpocket_detach);
diff --git a/sound/pcmcia/vx/vxp440.c b/sound/pcmcia/vx/vxp440.c
deleted file mode 100644
index 59190a833001..000000000000
--- a/sound/pcmcia/vx/vxp440.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#define COMPILE_VXP440
-
-/*
- add the following as /etc/pcmcia/vxp440.conf:
-
- device "snd-vxp440"
- class "audio" module "snd-vxp440"
-
- card "Digigram VX-POCKET440"
- manfid 0x01f1, 0x0100
- bind "snd-vxp440"
-*/
-
-#include "vxpocket.c"
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index ef6734271607..6f15c3d03ab5 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -49,7 +49,7 @@ static int vxp_reg_offset[VX_REG_MAX] = {
};
-inline static unsigned long vxp_reg_addr(vx_core_t *_chip, int reg)
+static inline unsigned long vxp_reg_addr(vx_core_t *_chip, int reg)
{
struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
return chip->port + vxp_reg_offset[reg];
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 62d6fa128148..1e8f16b4c073 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -24,21 +24,17 @@
#include <linux/moduleparam.h>
#include <sound/core.h>
#include "vxpocket.h"
+#include <pcmcia/ciscode.h>
+#include <pcmcia/cisreg.h>
#include <sound/initval.h>
/*
*/
-#ifdef COMPILE_VXP440
-#define CARD_NAME "VXPocket440"
-#else
-#define CARD_NAME "VXPocket"
-#endif
-
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("Digigram " CARD_NAME);
+MODULE_DESCRIPTION("Digigram VXPocket");
MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
+MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
@@ -46,82 +42,406 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */
static int ibl[SNDRV_CARDS];
module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(index, "Index value for VXPocket soundcard.");
module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(id, "ID string for VXPocket soundcard.");
module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(enable, "Enable VXPocket soundcard.");
module_param_array(ibl, int, NULL, 0444);
-MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(ibl, "Capture IBL size for VXPocket soundcard.");
/*
*/
-#ifdef COMPILE_VXP440
+static unsigned int card_alloc;
+static dev_link_t *dev_list; /* Linked list of devices */
+static dev_info_t dev_info = "snd-vxpocket";
-/* 1 DSP, 1 sync UER, 1 sync World Clock (NIY) */
-/* SMPTE (NIY) */
-/* 2 stereo analog input (line/micro) */
-/* 2 stereo analog output */
-/* Only output levels can be modified */
-/* UER, but only for the first two inputs and outputs. */
-#define NUM_CODECS 2
-#define CARD_TYPE VX_TYPE_VXP440
-#define DEV_INFO "snd-vxp440"
+static int vxpocket_event(event_t event, int priority, event_callback_args_t *args);
-#else
-/* 1 DSP, 1 sync UER */
-/* 1 programmable clock (NIY) */
-/* 1 stereo analog input (line/micro) */
-/* 1 stereo analog output */
-/* Only output levels can be modified */
+/*
+ */
+static void vxpocket_release(dev_link_t *link)
+{
+ if (link->state & DEV_CONFIG) {
+ /* release cs resources */
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+ }
+ if (link->handle) {
+ /* Break the link with Card Services */
+ pcmcia_deregister_client(link->handle);
+ link->handle = NULL;
+ }
+}
-#define NUM_CODECS 1
-#define CARD_TYPE VX_TYPE_VXPOCKET
-#define DEV_INFO "snd-vxpocket"
+/*
+ * destructor, called from snd_card_free_in_thread()
+ */
+static int snd_vxpocket_dev_free(snd_device_t *device)
+{
+ vx_core_t *chip = device->device_data;
-#endif
+ snd_vx_free_firmware(chip);
+ kfree(chip);
+ return 0;
+}
-static dev_info_t dev_info = DEV_INFO;
-static struct snd_vx_hardware vxp_hw = {
- .name = CARD_NAME,
- .type = CARD_TYPE,
+/*
+ * Hardware information
+ */
+
+/* VX-pocket V2
+ *
+ * 1 DSP, 1 sync UER
+ * 1 programmable clock (NIY)
+ * 1 stereo analog input (line/micro)
+ * 1 stereo analog output
+ * Only output levels can be modified
+ */
+
+static struct snd_vx_hardware vxpocket_hw = {
+ .name = "VXPocket",
+ .type = VX_TYPE_VXPOCKET,
/* hardware specs */
- .num_codecs = NUM_CODECS,
- .num_ins = NUM_CODECS,
- .num_outs = NUM_CODECS,
+ .num_codecs = 1,
+ .num_ins = 1,
+ .num_outs = 1,
.output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
};
-static struct snd_vxp_entry hw_entry = {
- .dev_info = &dev_info,
+/* VX-pocket 440
+ *
+ * 1 DSP, 1 sync UER, 1 sync World Clock (NIY)
+ * SMPTE (NIY)
+ * 2 stereo analog input (line/micro)
+ * 2 stereo analog output
+ * Only output levels can be modified
+ * UER, but only for the first two inputs and outputs.
+ */
- /* module parameters */
- .index_table = index,
- .id_table = id,
- .enable_table = enable,
- .ibl = ibl,
+static struct snd_vx_hardware vxp440_hw = {
+ .name = "VXPocket440",
+ .type = VX_TYPE_VXP440,
+
+ /* hardware specs */
+ .num_codecs = 2,
+ .num_ins = 2,
+ .num_outs = 2,
+ .output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
+};
+
+
+/*
+ * create vxpocket instance
+ */
+static struct snd_vxpocket *snd_vxpocket_new(snd_card_t *card, int ibl)
+{
+ client_reg_t client_reg; /* Register with cardmgr */
+ dev_link_t *link; /* Info for cardmgr */
+ vx_core_t *chip;
+ struct snd_vxpocket *vxp;
+ int ret;
+ static snd_device_ops_t ops = {
+ .dev_free = snd_vxpocket_dev_free,
+ };
+
+ chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops,
+ sizeof(struct snd_vxpocket) - sizeof(vx_core_t));
+ if (! chip)
+ return NULL;
+
+ if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
+ kfree(chip);
+ return NULL;
+ }
+ chip->ibl.size = ibl;
+
+ vxp = (struct snd_vxpocket *)chip;
+
+ link = &vxp->link;
+ link->priv = chip;
+
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ link->io.NumPorts1 = 16;
+
+ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ link->irq.Handler = &snd_vx_irq_handler;
+ link->irq.Instance = chip;
+
+ link->conf.Attributes = CONF_ENABLE_IRQ;
+ link->conf.Vcc = 50;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ link->conf.ConfigIndex = 1;
+ link->conf.Present = PRESENT_OPTION;
+
+ /* Register with Card Services */
+ memset(&client_reg, 0, sizeof(client_reg));
+ client_reg.dev_info = &dev_info;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
+#ifdef CONFIG_PM
+ | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
+ | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
+#endif
+ ;
+ client_reg.event_handler = &vxpocket_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+
+ ret = pcmcia_register_client(&link->handle, &client_reg);
+ if (ret != CS_SUCCESS) {
+ cs_error(link->handle, RegisterClient, ret);
+ return NULL;
+ }
+
+ return vxp;
+}
+
+
+/**
+ * snd_vxpocket_assign_resources - initialize the hardware and card instance.
+ * @port: i/o port for the card
+ * @irq: irq number for the card
+ *
+ * this function assigns the specified port and irq, boot the card,
+ * create pcm and control instances, and initialize the rest hardware.
+ *
+ * returns 0 if successful, or a negative error code.
+ */
+static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
+{
+ int err;
+ snd_card_t *card = chip->card;
+ struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+
+ snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
+ vxp->port = port;
+
+ sprintf(card->shortname, "Digigram %s", card->driver);
+ sprintf(card->longname, "%s at 0x%x, irq %i",
+ card->shortname, port, irq);
+
+ chip->irq = irq;
+
+ if ((err = snd_vx_setup_firmware(chip)) < 0)
+ return err;
+
+ return 0;
+}
+
+
+/*
+ * configuration callback
+ */
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void vxpocket_config(dev_link_t *link)
+{
+ client_handle_t handle = link->handle;
+ vx_core_t *chip = link->priv;
+ struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+ tuple_t tuple;
+ cisparse_t *parse;
+ u_short buf[32];
+ int last_fn, last_ret;
+
+ snd_printdd(KERN_DEBUG "vxpocket_config called\n");
+ parse = kmalloc(sizeof(*parse), GFP_KERNEL);
+ if (! parse) {
+ snd_printk(KERN_ERR "vx: cannot allocate\n");
+ return;
+ }
+ tuple.Attributes = 0;
+ tuple.TupleData = (cisdata_t *)buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+ link->conf.ConfigBase = parse->config.base;
+ link->conf.Present = parse->config.rmask[0];
+
+ /* redefine hardware record according to the VERSION1 string */
+ tuple.DesiredTuple = CISTPL_VERS_1;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+ if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) {
+ snd_printdd("VX-pocket is detected\n");
+ } else {
+ snd_printdd("VX-pocket 440 is detected\n");
+ /* overwrite the hardware information */
+ chip->hw = &vxp440_hw;
+ chip->type = vxp440_hw.type;
+ strcpy(chip->card->driver, vxp440_hw.name);
+ }
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+
+ chip->dev = &handle_to_dev(link->handle);
+ snd_card_set_dev(chip->card, chip->dev);
+
+ if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
+ goto failed;
+
+ link->dev = &vxp->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+ kfree(parse);
+ return;
+
+cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+failed:
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+ pcmcia_release_irq(link->handle, &link->irq);
+ link->state &= ~DEV_CONFIG;
+ kfree(parse);
+}
+
+
+/*
+ * event callback
+ */
+static int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+ vx_core_t *chip = link->priv;
+
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n");
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ chip->chip_status |= VX_STAT_IS_STALE;
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ vxpocket_config(link);
+ break;
+#ifdef CONFIG_PM
+ case CS_EVENT_PM_SUSPEND:
+ snd_printdd(KERN_DEBUG "SUSPEND\n");
+ link->state |= DEV_SUSPEND;
+ if (chip && chip->card->pm_suspend) {
+ snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
+ chip->card->pm_suspend(chip->card, PMSG_SUSPEND);
+ }
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
+ if (link->state & DEV_CONFIG)
+ pcmcia_release_configuration(link->handle);
+ break;
+ case CS_EVENT_PM_RESUME:
+ snd_printdd(KERN_DEBUG "RESUME\n");
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ snd_printdd(KERN_DEBUG "CARD_RESET\n");
+ if (DEV_OK(link)) {
+ //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+ snd_printdd(KERN_DEBUG "requestconfig...\n");
+ pcmcia_request_configuration(link->handle, &link->conf);
+ if (chip && chip->card->pm_resume) {
+ snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
+ chip->card->pm_resume(chip->card);
+ }
+ }
+ snd_printdd(KERN_DEBUG "resume done!\n");
+ break;
+#endif
+ }
+ return 0;
+}
- /* h/w config */
- .hardware = &vxp_hw,
- .ops = &snd_vxpocket_ops,
-};
/*
*/
-static dev_link_t *vxp_attach(void)
+static dev_link_t *vxpocket_attach(void)
{
- return snd_vxpocket_attach(&hw_entry);
+ snd_card_t *card;
+ struct snd_vxpocket *vxp;
+ int i;
+
+ /* find an empty slot from the card list */
+ for (i = 0; i < SNDRV_CARDS; i++) {
+ if (! card_alloc & (1 << i))
+ break;
+ }
+ if (i >= SNDRV_CARDS) {
+ snd_printk(KERN_ERR "vxpocket: too many cards found\n");
+ return NULL;
+ }
+ if (! enable[i])
+ return NULL; /* disabled explicitly */
+
+ /* ok, create a card instance */
+ card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+ if (card == NULL) {
+ snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
+ return NULL;
+ }
+
+ vxp = snd_vxpocket_new(card, ibl[i]);
+ if (! vxp) {
+ snd_card_free(card);
+ return NULL;
+ }
+
+ vxp->index = i;
+ card_alloc |= 1 << i;
+
+ /* Chain drivers */
+ vxp->link.next = dev_list;
+ dev_list = &vxp->link;
+
+ return &vxp->link;
}
-static void vxp_detach(dev_link_t *link)
+static void vxpocket_detach(dev_link_t *link)
{
- snd_vxpocket_detach(&hw_entry, link);
+ struct snd_vxpocket *vxp;
+ vx_core_t *chip;
+ dev_link_t **linkp;
+
+ if (! link)
+ return;
+
+ vxp = link->priv;
+ chip = (vx_core_t *)vxp;
+ card_alloc &= ~(1 << vxp->index);
+
+ /* Remove the interface data from the linked list */
+ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ if (*linkp == link) {
+ *linkp = link->next;
+ break;
+ }
+
+ chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
+ snd_card_disconnect(chip->card);
+ vxpocket_release(link);
+ snd_card_free_in_thread(chip->card);
}
/*
@@ -137,10 +457,11 @@ MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
static struct pcmcia_driver vxp_cs_driver = {
.owner = THIS_MODULE,
.drv = {
- .name = DEV_INFO,
+ .name = "snd-vxpocket",
},
- .attach = vxp_attach,
- .detach = vxp_detach,
+ .attach = vxpocket_attach,
+ .detach = vxpocket_detach,
+ .event = vxpocket_event,
.id_table = vxp_ids,
};
@@ -152,7 +473,7 @@ static int __init init_vxpocket(void)
static void __exit exit_vxpocket(void)
{
pcmcia_unregister_driver(&vxp_cs_driver);
- BUG_ON(hw_entry.dev_list != NULL);
+ BUG_ON(dev_list != NULL);
}
module_init(init_vxpocket);
diff --git a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h
index 4462c04a4e8f..70754aa3dd11 100644
--- a/sound/pcmcia/vx/vxpocket.h
+++ b/sound/pcmcia/vx/vxpocket.h
@@ -28,24 +28,6 @@
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
-struct snd_vxp_entry {
- dev_info_t *dev_info;
-
- /* module parameters */
- int *index_table;
- char **id_table;
- int *enable_table;
- int *ibl;
-
- /* h/w config */
- struct snd_vx_hardware *hardware;
- struct snd_vx_ops *ops;
-
- /* slots */
- vx_core_t *card_list[SNDRV_CARDS];
- dev_link_t *dev_list; /* Linked list of devices */
-};
-
struct snd_vxpocket {
vx_core_t core;
@@ -57,8 +39,7 @@ struct snd_vxpocket {
unsigned int regCDSP; /* current CDSP register */
unsigned int regDIALOG; /* current DIALOG register */
- int index;
- struct snd_vxp_entry *hw_entry;
+ int index; /* card index */
/* pcmcia stuff */
dev_link_t link;
@@ -70,12 +51,6 @@ extern struct snd_vx_ops snd_vxpocket_ops;
void vx_set_mic_boost(vx_core_t *chip, int boost);
void vx_set_mic_level(vx_core_t *chip, int level);
-/*
- * pcmcia stuff
- */
-dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw);
-void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link);
-
int vxp_add_mic_controls(vx_core_t *chip);
/* Constants used to access the CDSP register (0x08). */
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 061e52d3d771..758ca1bcbcf2 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -103,7 +103,7 @@ static void screamer_recalibrate(pmac_t *chip)
snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
if (chip->manufacturer == 0x1)
/* delay for broken crystal part */
- big_mdelay(750);
+ msleep(750);
snd_pmac_awacs_write_noreg(chip, 1,
chip->awacs_reg[1] | MASK_RECALIBRATE | MASK_CMUTE | MASK_AMUTE);
snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
@@ -653,10 +653,10 @@ static void snd_pmac_awacs_resume(pmac_t *chip)
{
if (machine_is_compatible("PowerBook3,1")
|| machine_is_compatible("PowerBook3,2")) {
- big_mdelay(100);
+ msleep(100);
snd_pmac_awacs_write_reg(chip, 1,
chip->awacs_reg[1] & ~MASK_PAROUT);
- big_mdelay(300);
+ msleep(300);
}
awacs_restore_all_regs(chip);
diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c
index 3f837d9f3eb1..edbc0484e22a 100644
--- a/sound/ppc/burgundy.c
+++ b/sound/ppc/burgundy.c
@@ -30,7 +30,7 @@
/* Waits for busy flag to clear */
-inline static void
+static inline void
snd_pmac_burgundy_busy_wait(pmac_t *chip)
{
int timeout = 50;
@@ -40,7 +40,7 @@ snd_pmac_burgundy_busy_wait(pmac_t *chip)
printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
}
-inline static void
+static inline void
snd_pmac_burgundy_extend_wait(pmac_t *chip)
{
int timeout;
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 75b8b7423036..c89e82eb06a6 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -153,7 +153,7 @@ static pmac_stream_t *snd_pmac_get_stream(pmac_t *chip, int stream)
/*
* wait while run status is on
*/
-inline static void
+static inline void
snd_pmac_wait_ack(pmac_stream_t *rec)
{
int timeout = 50000;
@@ -177,7 +177,7 @@ static void snd_pmac_pcm_set_format(pmac_t *chip)
/*
* stop the DMA transfer
*/
-inline static void snd_pmac_dma_stop(pmac_stream_t *rec)
+static inline void snd_pmac_dma_stop(pmac_stream_t *rec)
{
out_le32(&rec->dma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
snd_pmac_wait_ack(rec);
@@ -186,7 +186,7 @@ inline static void snd_pmac_dma_stop(pmac_stream_t *rec)
/*
* set the command pointer address
*/
-inline static void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cmd)
+static inline void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cmd)
{
out_le32(&rec->dma->cmdptr, cmd->addr);
}
@@ -194,7 +194,7 @@ inline static void snd_pmac_dma_set_command(pmac_stream_t *rec, pmac_dbdma_t *cm
/*
* start the DMA
*/
-inline static void snd_pmac_dma_run(pmac_stream_t *rec, int status)
+static inline void snd_pmac_dma_run(pmac_stream_t *rec, int status)
{
out_le32(&rec->dma->control, status | (status << 16));
}
@@ -765,7 +765,8 @@ snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
*/
static void snd_pmac_sound_feature(pmac_t *chip, int enable)
{
- ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);
+ if (ppc_md.feature_call)
+ ppc_md.feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, chip->node, 0, enable);
}
/*
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 582db5220119..ae3bb6c6edff 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -212,9 +212,4 @@ int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *ui
int snd_pmac_add_automute(pmac_t *chip);
-#define big_mdelay(msec) do {\
- set_current_state(TASK_UNINTERRUPTIBLE);\
- schedule_timeout(((msec) * HZ + 999) / 1000);\
-} while (0)
-
#endif /* __PMAC_H */
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 36c5d5d45bb1..b94437c024b1 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -945,7 +945,7 @@ static void device_change_handler(void *self)
check_mute(chip, &mix->line_mute, 0, mix->auto_mute_notify,
chip->lineout_sw_ctl);
if (mix->anded_reset)
- big_mdelay(10);
+ msleep(10);
check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
chip->speaker_sw_ctl);
mix->drc_enable = 0;
@@ -954,7 +954,7 @@ static void device_change_handler(void *self)
check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify,
chip->speaker_sw_ctl);
if (mix->anded_reset)
- big_mdelay(10);
+ msleep(10);
check_mute(chip, &mix->hp_mute, 1, mix->auto_mute_notify,
chip->master_sw_ctl);
if (mix->line_mute.addr != 0)
@@ -1109,22 +1109,22 @@ static void tumbler_reset_audio(pmac_t *chip)
DBG("(I) codec anded reset !\n");
write_audio_gpio(&mix->hp_mute, 0);
write_audio_gpio(&mix->amp_mute, 0);
- big_mdelay(200);
+ msleep(200);
write_audio_gpio(&mix->hp_mute, 1);
write_audio_gpio(&mix->amp_mute, 1);
- big_mdelay(100);
+ msleep(100);
write_audio_gpio(&mix->hp_mute, 0);
write_audio_gpio(&mix->amp_mute, 0);
- big_mdelay(100);
+ msleep(100);
} else {
DBG("(I) codec normal reset !\n");
write_audio_gpio(&mix->audio_reset, 0);
- big_mdelay(200);
+ msleep(200);
write_audio_gpio(&mix->audio_reset, 1);
- big_mdelay(100);
+ msleep(100);
write_audio_gpio(&mix->audio_reset, 0);
- big_mdelay(100);
+ msleep(100);
}
}
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 21a69e096225..954f994592ab 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(sound_loader_lock);
* list. Acquires locks as needed
*/
-static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
+static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
{
struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
int r;
@@ -175,7 +175,7 @@ static int sound_insert_unit(struct sound_unit **list, struct file_operations *f
devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
S_IFCHR | mode, s->name);
class_device_create(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor),
- NULL, s->name+6);
+ dev, s->name+6);
return r;
fail:
@@ -227,16 +227,18 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
static struct sound_unit *chains[SOUND_STEP];
/**
- * register_sound_special - register a special sound node
+ * register_sound_special_device - register a special sound node
* @fops: File operations for the driver
* @unit: Unit number to allocate
+ * @dev: device pointer
*
* Allocate a special sound device by minor number from the sound
* subsystem. The allocated number is returned on succes. On failure
* a negative error code is returned.
*/
-int register_sound_special(struct file_operations *fops, int unit)
+int register_sound_special_device(struct file_operations *fops, int unit,
+ struct device *dev)
{
const int chain = unit % SOUND_STEP;
int max_unit = 128 + chain;
@@ -294,9 +296,16 @@ int register_sound_special(struct file_operations *fops, int unit)
break;
}
return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
- name, S_IRUSR | S_IWUSR);
+ name, S_IRUSR | S_IWUSR, dev);
}
+EXPORT_SYMBOL(register_sound_special_device);
+
+int register_sound_special(struct file_operations *fops, int unit)
+{
+ return register_sound_special_device(fops, unit, NULL);
+}
+
EXPORT_SYMBOL(register_sound_special);
/**
@@ -312,7 +321,7 @@ EXPORT_SYMBOL(register_sound_special);
int register_sound_mixer(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[0], fops, dev, 0, 128,
- "mixer", S_IRUSR | S_IWUSR);
+ "mixer", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_mixer);
@@ -330,7 +339,7 @@ EXPORT_SYMBOL(register_sound_mixer);
int register_sound_midi(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[2], fops, dev, 2, 130,
- "midi", S_IRUSR | S_IWUSR);
+ "midi", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_midi);
@@ -356,7 +365,7 @@ EXPORT_SYMBOL(register_sound_midi);
int register_sound_dsp(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[3], fops, dev, 3, 131,
- "dsp", S_IWUSR | S_IRUSR);
+ "dsp", S_IWUSR | S_IRUSR, NULL);
}
EXPORT_SYMBOL(register_sound_dsp);
@@ -375,7 +384,7 @@ EXPORT_SYMBOL(register_sound_dsp);
int register_sound_synth(struct file_operations *fops, int dev)
{
return sound_insert_unit(&chains[9], fops, dev, 9, 137,
- "synth", S_IRUSR | S_IWUSR);
+ "synth", S_IRUSR | S_IWUSR, NULL);
}
EXPORT_SYMBOL(register_sound_synth);
diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig
index 2358df1c45a9..25a8a558ef92 100644
--- a/sound/sparc/Kconfig
+++ b/sound/sparc/Kconfig
@@ -7,12 +7,30 @@ config SND_SUN_AMD7930
tristate "Sun AMD7930"
depends on SBUS && SND
select SND_PCM
+ help
+ Say Y here to include support for AMD7930 sound device on Sun.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-sun-amd7930.
-# dep_tristate 'Sun DBRI' CONFIG_SND_SUN_DBRI $CONFIG_SND
config SND_SUN_CS4231
tristate "Sun CS4231"
depends on SND
select SND_PCM
+ help
+ Say Y here to include support for CS4231 sound device on Sun.
-endmenu
+ To compile this driver as a module, choose M here: the module
+ will be called snd-sun-cs4231.
+
+config SND_SUN_DBRI
+ tristate "Sun DBRI"
+ depends on SND && SBUS
+ select SND_PCM
+ help
+ Say Y here to include support for DBRI sound device on Sun.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-sun-dbri.
+endmenu
diff --git a/sound/sparc/Makefile b/sound/sparc/Makefile
index 6809cc92d276..3cd89c67c2f2 100644
--- a/sound/sparc/Makefile
+++ b/sound/sparc/Makefile
@@ -4,9 +4,9 @@
#
snd-sun-amd7930-objs := amd7930.o
-#snd-sun-dbri-objs := dbri.o
snd-sun-cs4231-objs := cs4231.o
+snd-sun-dbri-objs := dbri.o
obj-$(CONFIG_SND_SUN_AMD7930) += snd-sun-amd7930.o
-#obj-$(CONFIG_SND_SUN_DBRI) += snd-sun-dbri.o
obj-$(CONFIG_SND_SUN_CS4231) += snd-sun-cs4231.o
+obj-$(CONFIG_SND_SUN_DBRI) += snd-sun-dbri.o
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
new file mode 100644
index 000000000000..941c7b1e7ebb
--- /dev/null
+++ b/sound/sparc/dbri.c
@@ -0,0 +1,2729 @@
+/*
+ * Driver for DBRI sound chip found on Sparcs.
+ * Copyright (C) 2004 Martin Habets (mhabets@users.sourceforge.net)
+ *
+ * Based entirely upon drivers/sbus/audio/dbri.c which is:
+ * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
+ * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org)
+ *
+ * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO
+ * on Sun SPARCstation 10, 20, LX and Voyager models.
+ *
+ * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel
+ * data time multiplexer with ISDN support (aka T7259)
+ * Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel.
+ * CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?).
+ * Documentation:
+ * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Tranceiver" from
+ * Sparc Technology Business (courtesy of Sun Support)
+ * - Data sheet of the T7903, a newer but very similar ISA bus equivalent
+ * available from the Lucent (formarly AT&T microelectronics) home
+ * page.
+ * - http://www.freesoft.org/Linux/DBRI/
+ * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec
+ * Interfaces: CHI, Audio In & Out, 2 bits parallel
+ * Documentation: from the Crystal Semiconductor home page.
+ *
+ * The DBRI is a 32 pipe machine, each pipe can transfer some bits between
+ * memory and a serial device (long pipes, nr 0-15) or between two serial
+ * devices (short pipes, nr 16-31), or simply send a fixed data to a serial
+ * device (short pipes).
+ * A timeslot defines the bit-offset and nr of bits read from a serial device.
+ * The timeslots are linked to 6 circular lists, one for each direction for
+ * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes
+ * (the second one is a monitor/tee pipe, valid only for serial input).
+ *
+ * The mmcodec is connected via the CHI bus and needs the data & some
+ * parameters (volume, balance, output selection) timemultiplexed in 8 byte
+ * chunks. It also has a control mode, which serves for audio format setting.
+ *
+ * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
+ * the same CHI bus, so I thought perhaps it is possible to use the onboard
+ * & the speakerbox codec simultanously, giving 2 (not very independent :-)
+ * audio devices. But the SUN HW group decided against it, at least on my
+ * LX the speakerbox connector has at least 1 pin missing and 1 wrongly
+ * connected.
+ */
+
+#include <sound/driver.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/atomic.h>
+
+MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
+MODULE_DESCRIPTION("Sun DBRI");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
+
+#define DBRI_DEBUG
+
+#define D_INT (1<<0)
+#define D_GEN (1<<1)
+#define D_CMD (1<<2)
+#define D_MM (1<<3)
+#define D_USR (1<<4)
+#define D_DESC (1<<5)
+
+static int dbri_debug = 0;
+module_param(dbri_debug, int, 0444);
+MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
+
+#ifdef DBRI_DEBUG
+static char *cmds[] = {
+ "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
+ "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
+};
+
+#define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x)
+
+#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
+ (1 << 27) | \
+ value)
+#else
+#define dprintk(a, x...)
+
+#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
+ (intr << 27) | \
+ value)
+#endif /* DBRI_DEBUG */
+
+/***************************************************************************
+ CS4215 specific definitions and structures
+****************************************************************************/
+
+struct cs4215 {
+ __u8 data[4]; /* Data mode: Time slots 5-8 */
+ __u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */
+ __u8 onboard;
+ __u8 offset; /* Bit offset from frame sync to time slot 1 */
+ volatile __u32 status;
+ volatile __u32 version;
+ __u8 precision; /* In bits, either 8 or 16 */
+ __u8 channels; /* 1 or 2 */
+};
+
+/*
+ * Control mode first
+ */
+
+/* Time Slot 1, Status register */
+#define CS4215_CLB (1<<2) /* Control Latch Bit */
+#define CS4215_OLB (1<<3) /* 1: line: 2.0V, speaker 4V */
+ /* 0: line: 2.8V, speaker 8V */
+#define CS4215_MLB (1<<4) /* 1: Microphone: 20dB gain disabled */
+#define CS4215_RSRVD_1 (1<<5)
+
+/* Time Slot 2, Data Format Register */
+#define CS4215_DFR_LINEAR16 0
+#define CS4215_DFR_ULAW 1
+#define CS4215_DFR_ALAW 2
+#define CS4215_DFR_LINEAR8 3
+#define CS4215_DFR_STEREO (1<<2)
+static struct {
+ unsigned short freq;
+ unsigned char xtal;
+ unsigned char csval;
+} CS4215_FREQ[] = {
+ { 8000, (1 << 4), (0 << 3) },
+ { 16000, (1 << 4), (1 << 3) },
+ { 27429, (1 << 4), (2 << 3) }, /* Actually 24428.57 */
+ { 32000, (1 << 4), (3 << 3) },
+ /* { NA, (1 << 4), (4 << 3) }, */
+ /* { NA, (1 << 4), (5 << 3) }, */
+ { 48000, (1 << 4), (6 << 3) },
+ { 9600, (1 << 4), (7 << 3) },
+ { 5513, (2 << 4), (0 << 3) }, /* Actually 5512.5 */
+ { 11025, (2 << 4), (1 << 3) },
+ { 18900, (2 << 4), (2 << 3) },
+ { 22050, (2 << 4), (3 << 3) },
+ { 37800, (2 << 4), (4 << 3) },
+ { 44100, (2 << 4), (5 << 3) },
+ { 33075, (2 << 4), (6 << 3) },
+ { 6615, (2 << 4), (7 << 3) },
+ { 0, 0, 0}
+};
+
+#define CS4215_HPF (1<<7) /* High Pass Filter, 1: Enabled */
+
+#define CS4215_12_MASK 0xfcbf /* Mask off reserved bits in slot 1 & 2 */
+
+/* Time Slot 3, Serial Port Control register */
+#define CS4215_XEN (1<<0) /* 0: Enable serial output */
+#define CS4215_XCLK (1<<1) /* 1: Master mode: Generate SCLK */
+#define CS4215_BSEL_64 (0<<2) /* Bitrate: 64 bits per frame */
+#define CS4215_BSEL_128 (1<<2)
+#define CS4215_BSEL_256 (2<<2)
+#define CS4215_MCK_MAST (0<<4) /* Master clock */
+#define CS4215_MCK_XTL1 (1<<4) /* 24.576 MHz clock source */
+#define CS4215_MCK_XTL2 (2<<4) /* 16.9344 MHz clock source */
+#define CS4215_MCK_CLK1 (3<<4) /* Clockin, 256 x Fs */
+#define CS4215_MCK_CLK2 (4<<4) /* Clockin, see DFR */
+
+/* Time Slot 4, Test Register */
+#define CS4215_DAD (1<<0) /* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */
+#define CS4215_ENL (1<<1) /* Enable Loopback Testing */
+
+/* Time Slot 5, Parallel Port Register */
+/* Read only here and the same as the in data mode */
+
+/* Time Slot 6, Reserved */
+
+/* Time Slot 7, Version Register */
+#define CS4215_VERSION_MASK 0xf /* Known versions 0/C, 1/D, 2/E */
+
+/* Time Slot 8, Reserved */
+
+/*
+ * Data mode
+ */
+/* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data */
+
+/* Time Slot 5, Output Setting */
+#define CS4215_LO(v) v /* Left Output Attenuation 0x3f: -94.5 dB */
+#define CS4215_LE (1<<6) /* Line Out Enable */
+#define CS4215_HE (1<<7) /* Headphone Enable */
+
+/* Time Slot 6, Output Setting */
+#define CS4215_RO(v) v /* Right Output Attenuation 0x3f: -94.5 dB */
+#define CS4215_SE (1<<6) /* Speaker Enable */
+#define CS4215_ADI (1<<7) /* A/D Data Invalid: Busy in calibration */
+
+/* Time Slot 7, Input Setting */
+#define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */
+#define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */
+#define CS4215_OVR (1<<5) /* 1: Overrange condition occurred */
+#define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */
+#define CS4215_PIO1 (1<<7)
+
+/* Time Slot 8, Input Setting */
+#define CS4215_RG(v) v /* Right Gain Setting 0xf: 22.5 dB */
+#define CS4215_MA(v) (v<<4) /* Monitor Path Attenuation 0xf: mute */
+
+/***************************************************************************
+ DBRI specific definitions and structures
+****************************************************************************/
+
+/* DBRI main registers */
+#define REG0 0x00UL /* Status and Control */
+#define REG1 0x04UL /* Mode and Interrupt */
+#define REG2 0x08UL /* Parallel IO */
+#define REG3 0x0cUL /* Test */
+#define REG8 0x20UL /* Command Queue Pointer */
+#define REG9 0x24UL /* Interrupt Queue Pointer */
+
+#define DBRI_NO_CMDS 64
+#define DBRI_NO_INTS 1 /* Note: the value of this define was
+ * originally 2. The ringbuffer to store
+ * interrupts in dma is currently broken.
+ * This is a temporary fix until the ringbuffer
+ * is fixed.
+ */
+#define DBRI_INT_BLK 64
+#define DBRI_NO_DESCS 64
+#define DBRI_NO_PIPES 32
+
+#define DBRI_MM_ONB 1
+#define DBRI_MM_SB 2
+
+#define DBRI_REC 0
+#define DBRI_PLAY 1
+#define DBRI_NO_STREAMS 2
+
+/* One transmit/receive descriptor */
+struct dbri_mem {
+ volatile __u32 word1;
+ volatile __u32 ba; /* Transmit/Receive Buffer Address */
+ volatile __u32 nda; /* Next Descriptor Address */
+ volatile __u32 word4;
+};
+
+/* This structure is in a DMA region where it can accessed by both
+ * the CPU and the DBRI
+ */
+struct dbri_dma {
+ volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands */
+ volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK]; /* Interrupt field */
+ struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */
+};
+
+#define dbri_dma_off(member, elem) \
+ ((u32)(unsigned long) \
+ (&(((struct dbri_dma *)0)->member[elem])))
+
+enum in_or_out { PIPEinput, PIPEoutput };
+
+struct dbri_pipe {
+ u32 sdp; /* SDP command word */
+ enum in_or_out direction;
+ int nextpipe; /* Next pipe in linked list */
+ int prevpipe;
+ int cycle; /* Offset of timeslot (bits) */
+ int length; /* Length of timeslot (bits) */
+ int first_desc; /* Index of first descriptor */
+ int desc; /* Index of active descriptor */
+ volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
+};
+
+struct dbri_desc {
+ int inuse; /* Boolean flag */
+ int next; /* Index of next desc, or -1 */
+ unsigned int len;
+};
+
+/* Per stream (playback or record) information */
+typedef struct dbri_streaminfo {
+ snd_pcm_substream_t *substream;
+ u32 dvma_buffer; /* Device view of Alsa DMA buffer */
+ int left; /* # of bytes left in DMA buffer */
+ int size; /* Size of DMA buffer */
+ size_t offset; /* offset in user buffer */
+ int pipe; /* Data pipe used */
+ int left_gain; /* mixer elements */
+ int right_gain;
+ int balance;
+} dbri_streaminfo_t;
+
+/* This structure holds the information for both chips (DBRI & CS4215) */
+typedef struct snd_dbri {
+ snd_card_t *card; /* ALSA card */
+ snd_pcm_t *pcm;
+
+ int regs_size, irq; /* Needed for unload */
+ struct sbus_dev *sdev; /* SBUS device info */
+ spinlock_t lock;
+
+ volatile struct dbri_dma *dma; /* Pointer to our DMA block */
+ u32 dma_dvma; /* DBRI visible DMA address */
+
+ void __iomem *regs; /* dbri HW regs */
+ int dbri_version; /* 'e' and up is OK */
+ int dbri_irqp; /* intr queue pointer */
+ int wait_seen;
+
+ struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */
+ struct dbri_desc descs[DBRI_NO_DESCS];
+
+ int chi_in_pipe;
+ int chi_out_pipe;
+ int chi_bpf;
+
+ struct cs4215 mm; /* mmcodec special info */
+ /* per stream (playback/record) info */
+ struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];
+
+ struct snd_dbri *next;
+} snd_dbri_t;
+
+/* Needed for the ALSA macros to work */
+#define chip_t snd_dbri_t
+
+#define DBRI_MAX_VOLUME 63 /* Output volume */
+#define DBRI_MAX_GAIN 15 /* Input gain */
+#define DBRI_RIGHT_BALANCE 255
+#define DBRI_MID_BALANCE (DBRI_RIGHT_BALANCE >> 1)
+
+/* DBRI Reg0 - Status Control Register - defines. (Page 17) */
+#define D_P (1<<15) /* Program command & queue pointer valid */
+#define D_G (1<<14) /* Allow 4-Word SBus Burst */
+#define D_S (1<<13) /* Allow 16-Word SBus Burst */
+#define D_E (1<<12) /* Allow 8-Word SBus Burst */
+#define D_X (1<<7) /* Sanity Timer Disable */
+#define D_T (1<<6) /* Permit activation of the TE interface */
+#define D_N (1<<5) /* Permit activation of the NT interface */
+#define D_C (1<<4) /* Permit activation of the CHI interface */
+#define D_F (1<<3) /* Force Sanity Timer Time-Out */
+#define D_D (1<<2) /* Disable Master Mode */
+#define D_H (1<<1) /* Halt for Analysis */
+#define D_R (1<<0) /* Soft Reset */
+
+/* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */
+#define D_LITTLE_END (1<<8) /* Byte Order */
+#define D_BIG_END (0<<8) /* Byte Order */
+#define D_MRR (1<<4) /* Multiple Error Ack on SBus (readonly) */
+#define D_MLE (1<<3) /* Multiple Late Error on SBus (readonly) */
+#define D_LBG (1<<2) /* Lost Bus Grant on SBus (readonly) */
+#define D_MBE (1<<1) /* Burst Error on SBus (readonly) */
+#define D_IR (1<<0) /* Interrupt Indicator (readonly) */
+
+/* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */
+#define D_ENPIO3 (1<<7) /* Enable Pin 3 */
+#define D_ENPIO2 (1<<6) /* Enable Pin 2 */
+#define D_ENPIO1 (1<<5) /* Enable Pin 1 */
+#define D_ENPIO0 (1<<4) /* Enable Pin 0 */
+#define D_ENPIO (0xf0) /* Enable all the pins */
+#define D_PIO3 (1<<3) /* Pin 3: 1: Data mode, 0: Ctrl mode */
+#define D_PIO2 (1<<2) /* Pin 2: 1: Onboard PDN */
+#define D_PIO1 (1<<1) /* Pin 1: 0: Reset */
+#define D_PIO0 (1<<0) /* Pin 0: 1: Speakerbox PDN */
+
+/* DBRI Commands (Page 20) */
+#define D_WAIT 0x0 /* Stop execution */
+#define D_PAUSE 0x1 /* Flush long pipes */
+#define D_JUMP 0x2 /* New command queue */
+#define D_IIQ 0x3 /* Initialize Interrupt Queue */
+#define D_REX 0x4 /* Report command execution via interrupt */
+#define D_SDP 0x5 /* Setup Data Pipe */
+#define D_CDP 0x6 /* Continue Data Pipe (reread NULL Pointer) */
+#define D_DTS 0x7 /* Define Time Slot */
+#define D_SSP 0x8 /* Set short Data Pipe */
+#define D_CHI 0x9 /* Set CHI Global Mode */
+#define D_NT 0xa /* NT Command */
+#define D_TE 0xb /* TE Command */
+#define D_CDEC 0xc /* Codec setup */
+#define D_TEST 0xd /* No comment */
+#define D_CDM 0xe /* CHI Data mode command */
+
+/* Special bits for some commands */
+#define D_PIPE(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */
+
+/* Setup Data Pipe */
+/* IRM */
+#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value rcvd */
+#define D_SDP_CHANGE (2<<18) /* Report any changes */
+#define D_SDP_EVERY (3<<18) /* Report any changes */
+#define D_SDP_EOL (1<<17) /* EOL interrupt enable */
+#define D_SDP_IDLE (1<<16) /* HDLC idle interrupt enable */
+
+/* Pipe data MODE */
+#define D_SDP_MEM (0<<13) /* To/from memory */
+#define D_SDP_HDLC (2<<13)
+#define D_SDP_HDLC_D (3<<13) /* D Channel (prio control) */
+#define D_SDP_SER (4<<13) /* Serial to serial */
+#define D_SDP_FIXED (6<<13) /* Short only */
+#define D_SDP_MODE(v) ((v)&(7<<13))
+
+#define D_SDP_TO_SER (1<<12) /* Direction */
+#define D_SDP_FROM_SER (0<<12) /* Direction */
+#define D_SDP_MSB (1<<11) /* Bit order within Byte */
+#define D_SDP_LSB (0<<11) /* Bit order within Byte */
+#define D_SDP_P (1<<10) /* Pointer Valid */
+#define D_SDP_A (1<<8) /* Abort */
+#define D_SDP_C (1<<7) /* Clear */
+
+/* Define Time Slot */
+#define D_DTS_VI (1<<17) /* Valid Input Time-Slot Descriptor */
+#define D_DTS_VO (1<<16) /* Valid Output Time-Slot Descriptor */
+#define D_DTS_INS (1<<15) /* Insert Time Slot */
+#define D_DTS_DEL (0<<15) /* Delete Time Slot */
+#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */
+#define D_DTS_PRVOUT(v) ((v)<<5) /* Previous Out Pipe */
+
+/* Time Slot defines */
+#define D_TS_LEN(v) ((v)<<24) /* Number of bits in this time slot */
+#define D_TS_CYCLE(v) ((v)<<14) /* Bit Count at start of TS */
+#define D_TS_DI (1<<13) /* Data Invert */
+#define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */
+#define D_TS_MONITOR (2<<10) /* Monitor pipe */
+#define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */
+#define D_TS_ANCHOR (7<<10) /* Starting short pipes */
+#define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */
+#define D_TS_NEXT(v) ((v)<<0) /* Pipe Nr: 0-15 long, 16-21 short */
+
+/* Concentration Highway Interface Modes */
+#define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */
+#define D_CHI_IR (1<<15) /* Immediate Interrupt Report */
+#define D_CHI_EN (1<<14) /* CHIL Interrupt enabled */
+#define D_CHI_OD (1<<13) /* Open Drain Enable */
+#define D_CHI_FE (1<<12) /* Sample CHIFS on Rising Frame Edge */
+#define D_CHI_FD (1<<11) /* Frame Drive */
+#define D_CHI_BPF(v) ((v)<<0) /* Bits per Frame */
+
+/* NT: These are here for completeness */
+#define D_NT_FBIT (1<<17) /* Frame Bit */
+#define D_NT_NBF (1<<16) /* Number of bad frames to loose framing */
+#define D_NT_IRM_IMM (1<<15) /* Interrupt Report & Mask: Immediate */
+#define D_NT_IRM_EN (1<<14) /* Interrupt Report & Mask: Enable */
+#define D_NT_ISNT (1<<13) /* Configfure interface as NT */
+#define D_NT_FT (1<<12) /* Fixed Timing */
+#define D_NT_EZ (1<<11) /* Echo Channel is Zeros */
+#define D_NT_IFA (1<<10) /* Inhibit Final Activation */
+#define D_NT_ACT (1<<9) /* Activate Interface */
+#define D_NT_MFE (1<<8) /* Multiframe Enable */
+#define D_NT_RLB(v) ((v)<<5) /* Remote Loopback */
+#define D_NT_LLB(v) ((v)<<2) /* Local Loopback */
+#define D_NT_FACT (1<<1) /* Force Activation */
+#define D_NT_ABV (1<<0) /* Activate Bipolar Violation */
+
+/* Codec Setup */
+#define D_CDEC_CK(v) ((v)<<24) /* Clock Select */
+#define D_CDEC_FED(v) ((v)<<12) /* FSCOD Falling Edge Delay */
+#define D_CDEC_RED(v) ((v)<<0) /* FSCOD Rising Edge Delay */
+
+/* Test */
+#define D_TEST_RAM(v) ((v)<<16) /* RAM Pointer */
+#define D_TEST_SIZE(v) ((v)<<11) /* */
+#define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */
+#define D_TEST_PROC 0x6 /* MicroProcessor test */
+#define D_TEST_SER 0x7 /* Serial-Controller test */
+#define D_TEST_RAMREAD 0x8 /* Copy from Ram to system memory */
+#define D_TEST_RAMWRITE 0x9 /* Copy into Ram from system memory */
+#define D_TEST_RAMBIST 0xa /* RAM Built-In Self Test */
+#define D_TEST_MCBIST 0xb /* Microcontroller Built-In Self Test */
+#define D_TEST_DUMP 0xe /* ROM Dump */
+
+/* CHI Data Mode */
+#define D_CDM_THI (1<<8) /* Transmit Data on CHIDR Pin */
+#define D_CDM_RHI (1<<7) /* Receive Data on CHIDX Pin */
+#define D_CDM_RCE (1<<6) /* Receive on Rising Edge of CHICK */
+#define D_CDM_XCE (1<<2) /* Transmit Data on Rising Edge of CHICK */
+#define D_CDM_XEN (1<<1) /* Transmit Highway Enable */
+#define D_CDM_REN (1<<0) /* Receive Highway Enable */
+
+/* The Interrupts */
+#define D_INTR_BRDY 1 /* Buffer Ready for processing */
+#define D_INTR_MINT 2 /* Marked Interrupt in RD/TD */
+#define D_INTR_IBEG 3 /* Flag to idle transition detected (HDLC) */
+#define D_INTR_IEND 4 /* Idle to flag transition detected (HDLC) */
+#define D_INTR_EOL 5 /* End of List */
+#define D_INTR_CMDI 6 /* Command has bean read */
+#define D_INTR_XCMP 8 /* Transmission of frame complete */
+#define D_INTR_SBRI 9 /* BRI status change info */
+#define D_INTR_FXDT 10 /* Fixed data change */
+#define D_INTR_CHIL 11 /* CHI lost frame sync (channel 36 only) */
+#define D_INTR_COLL 11 /* Unrecoverable D-Channel collision */
+#define D_INTR_DBYT 12 /* Dropped by frame slip */
+#define D_INTR_RBYT 13 /* Repeated by frame slip */
+#define D_INTR_LINT 14 /* Lost Interrupt */
+#define D_INTR_UNDR 15 /* DMA underrun */
+
+#define D_INTR_TE 32
+#define D_INTR_NT 34
+#define D_INTR_CHI 36
+#define D_INTR_CMD 38
+
+#define D_INTR_GETCHAN(v) (((v)>>24) & 0x3f)
+#define D_INTR_GETCODE(v) (((v)>>20) & 0xf)
+#define D_INTR_GETCMD(v) (((v)>>16) & 0xf)
+#define D_INTR_GETVAL(v) ((v) & 0xffff)
+#define D_INTR_GETRVAL(v) ((v) & 0xfffff)
+
+#define D_P_0 0 /* TE receive anchor */
+#define D_P_1 1 /* TE transmit anchor */
+#define D_P_2 2 /* NT transmit anchor */
+#define D_P_3 3 /* NT receive anchor */
+#define D_P_4 4 /* CHI send data */
+#define D_P_5 5 /* CHI receive data */
+#define D_P_6 6 /* */
+#define D_P_7 7 /* */
+#define D_P_8 8 /* */
+#define D_P_9 9 /* */
+#define D_P_10 10 /* */
+#define D_P_11 11 /* */
+#define D_P_12 12 /* */
+#define D_P_13 13 /* */
+#define D_P_14 14 /* */
+#define D_P_15 15 /* */
+#define D_P_16 16 /* CHI anchor pipe */
+#define D_P_17 17 /* CHI send */
+#define D_P_18 18 /* CHI receive */
+#define D_P_19 19 /* CHI receive */
+#define D_P_20 20 /* CHI receive */
+#define D_P_21 21 /* */
+#define D_P_22 22 /* */
+#define D_P_23 23 /* */
+#define D_P_24 24 /* */
+#define D_P_25 25 /* */
+#define D_P_26 26 /* */
+#define D_P_27 27 /* */
+#define D_P_28 28 /* */
+#define D_P_29 29 /* */
+#define D_P_30 30 /* */
+#define D_P_31 31 /* */
+
+/* Transmit descriptor defines */
+#define DBRI_TD_F (1<<31) /* End of Frame */
+#define DBRI_TD_D (1<<30) /* Do not append CRC */
+#define DBRI_TD_CNT(v) ((v)<<16) /* Number of valid bytes in the buffer */
+#define DBRI_TD_B (1<<15) /* Final interrupt */
+#define DBRI_TD_M (1<<14) /* Marker interrupt */
+#define DBRI_TD_I (1<<13) /* Transmit Idle Characters */
+#define DBRI_TD_FCNT(v) (v) /* Flag Count */
+#define DBRI_TD_UNR (1<<3) /* Underrun: transmitter is out of data */
+#define DBRI_TD_ABT (1<<2) /* Abort: frame aborted */
+#define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */
+#define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */
+ /* Maximum buffer size per TD: almost 8Kb */
+#define DBRI_TD_MAXCNT ((1 << 13) - 1)
+
+/* Receive descriptor defines */
+#define DBRI_RD_F (1<<31) /* End of Frame */
+#define DBRI_RD_C (1<<30) /* Completed buffer */
+#define DBRI_RD_B (1<<15) /* Final interrupt */
+#define DBRI_RD_M (1<<14) /* Marker interrupt */
+#define DBRI_RD_BCNT(v) (v) /* Buffer size */
+#define DBRI_RD_CRC (1<<7) /* 0: CRC is correct */
+#define DBRI_RD_BBC (1<<6) /* 1: Bad Byte received */
+#define DBRI_RD_ABT (1<<5) /* Abort: frame aborted */
+#define DBRI_RD_OVRN (1<<3) /* Overrun: data lost */
+#define DBRI_RD_STATUS(v) ((v)&0xff) /* Receive status */
+#define DBRI_RD_CNT(v) (((v)>>16)&0x1fff) /* Valid bytes in the buffer */
+
+/* stream_info[] access */
+/* Translate the ALSA direction into the array index */
+#define DBRI_STREAMNO(substream) \
+ (substream->stream == \
+ SNDRV_PCM_STREAM_PLAYBACK? DBRI_PLAY: DBRI_REC)
+
+/* Return a pointer to dbri_streaminfo */
+#define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)]
+
+static snd_dbri_t *dbri_list = NULL; /* All DBRI devices */
+
+/*
+ * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
+ * So we have to reverse the bits. Note: not all bit lengths are supported
+ */
+static __u32 reverse_bytes(__u32 b, int len)
+{
+ switch (len) {
+ case 32:
+ b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
+ case 16:
+ b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);
+ case 8:
+ b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);
+ case 4:
+ b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);
+ case 2:
+ b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
+ case 1:
+ case 0:
+ break;
+ default:
+ printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n");
+ };
+
+ return b;
+}
+
+/*
+****************************************************************************
+************** DBRI initialization and command synchronization *************
+****************************************************************************
+
+Commands are sent to the DBRI by building a list of them in memory,
+then writing the address of the first list item to DBRI register 8.
+The list is terminated with a WAIT command, which can generate a
+CPU interrupt if required.
+
+Since the DBRI can run in parallel with the CPU, several means of
+synchronization present themselves. The original scheme (Rudolf's)
+was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
+an interrupt signaled completion, and wait on a wait_queue if a routine
+attempted to cmdlock while the flag was set. The problems arose when
+we tried to cmdlock from inside an interrupt handler, which might
+cause scheduling in an interrupt (if we waited), etc, etc
+
+A more sophisticated scheme might involve a circular command buffer
+or an array of command buffers. A routine could fill one with
+commands and link it onto a list. When a interrupt signaled
+completion of the current command buffer, look on the list for
+the next one.
+
+I've decided to implement something much simpler - after each command,
+the CPU waits for the DBRI to finish the command by polling the P bit
+in DBRI register 0. I've tried to implement this in such a way
+that might make implementing a more sophisticated scheme easier.
+
+Every time a routine wants to write commands to the DBRI, it must
+first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
+in return. After the commands have been writen, dbri_cmdsend() is
+called with the final pointer value.
+
+*/
+
+enum dbri_lock_t { NoGetLock, GetLock };
+
+static volatile s32 *dbri_cmdlock(snd_dbri_t * dbri, enum dbri_lock_t get)
+{
+#ifndef SMP
+ if ((get == GetLock) && spin_is_locked(&dbri->lock)) {
+ printk(KERN_ERR "DBRI: cmdlock called while in spinlock.");
+ }
+#endif
+
+ /*if (get == GetLock) spin_lock(&dbri->lock); */
+ return &dbri->dma->cmd[0];
+}
+
+static void dbri_process_interrupt_buffer(snd_dbri_t *);
+
+static void dbri_cmdsend(snd_dbri_t * dbri, volatile s32 * cmd)
+{
+ int MAXLOOPS = 1000000;
+ int maxloops = MAXLOOPS;
+ volatile s32 *ptr;
+
+ for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) {
+ dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
+ }
+
+ if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) {
+ printk("DBRI: Command buffer overflow! (bug in driver)\n");
+ /* Ignore the last part. */
+ cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3];
+ }
+
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+ *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
+ dbri->wait_seen = 0;
+ sbus_writel(dbri->dma_dvma, dbri->regs + REG8);
+ while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P))
+ barrier();
+ if (maxloops == 0) {
+ printk(KERN_ERR "DBRI: Chip never completed command buffer\n");
+ dprintk(D_CMD, "DBRI: Chip never completed command buffer\n");
+ } else {
+ while ((--maxloops) > 0 && (!dbri->wait_seen))
+ dbri_process_interrupt_buffer(dbri);
+ if (maxloops == 0) {
+ printk(KERN_ERR "DBRI: Chip never acked WAIT\n");
+ dprintk(D_CMD, "DBRI: Chip never acked WAIT\n");
+ } else {
+ dprintk(D_CMD, "Chip completed command "
+ "buffer (%d)\n", MAXLOOPS - maxloops);
+ }
+ }
+
+ /*spin_unlock(&dbri->lock); */
+}
+
+/* Lock must be held when calling this */
+static void dbri_reset(snd_dbri_t * dbri)
+{
+ int i;
+
+ dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",
+ sbus_readl(dbri->regs + REG0),
+ sbus_readl(dbri->regs + REG2),
+ sbus_readl(dbri->regs + REG8), sbus_readl(dbri->regs + REG9));
+
+ sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */
+ for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
+ udelay(10);
+}
+
+/* Lock must not be held before calling this */
+static void dbri_initialize(snd_dbri_t * dbri)
+{
+ volatile s32 *cmd;
+ u32 dma_addr, tmp;
+ unsigned long flags;
+ int n;
+
+ spin_lock_irqsave(&dbri->lock, flags);
+
+ dbri_reset(dbri);
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+ dprintk(D_GEN, "init: cmd: %p, int: %p\n",
+ &dbri->dma->cmd[0], &dbri->dma->intr[0]);
+
+ /*
+ * Initialize the interrupt ringbuffer.
+ */
+ for (n = 0; n < DBRI_NO_INTS - 1; n++) {
+ dma_addr = dbri->dma_dvma;
+ dma_addr += dbri_dma_off(intr, ((n + 1) & DBRI_INT_BLK));
+ dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
+ }
+ dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
+ dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
+ dbri->dbri_irqp = 1;
+
+ /* Initialize pipes */
+ for (n = 0; n < DBRI_NO_PIPES; n++)
+ dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
+
+ /* We should query the openprom to see what burst sizes this
+ * SBus supports. For now, just disable all SBus bursts */
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~(D_G | D_S | D_E);
+ sbus_writel(tmp, dbri->regs + REG0);
+
+ /*
+ * Set up the interrupt queue
+ */
+ dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
+ *(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
+ *(cmd++) = dma_addr;
+
+ dbri_cmdsend(dbri, cmd);
+ spin_unlock_irqrestore(&dbri->lock, flags);
+}
+
+/*
+****************************************************************************
+************************** DBRI data pipe management ***********************
+****************************************************************************
+
+While DBRI control functions use the command and interrupt buffers, the
+main data path takes the form of data pipes, which can be short (command
+and interrupt driven), or long (attached to DMA buffers). These functions
+provide a rudimentary means of setting up and managing the DBRI's pipes,
+but the calling functions have to make sure they respect the pipes' linked
+list ordering, among other things. The transmit and receive functions
+here interface closely with the transmit and receive interrupt code.
+
+*/
+static int pipe_active(snd_dbri_t * dbri, int pipe)
+{
+ return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));
+}
+
+/* reset_pipe(dbri, pipe)
+ *
+ * Called on an in-use pipe to clear anything being transmitted or received
+ * Lock must be held before calling this.
+ */
+static void reset_pipe(snd_dbri_t * dbri, int pipe)
+{
+ int sdp;
+ int desc;
+ volatile int *cmd;
+
+ if (pipe < 0 || pipe > 31) {
+ printk("DBRI: reset_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ sdp = dbri->pipes[pipe].sdp;
+ if (sdp == 0) {
+ printk("DBRI: reset_pipe called on uninitialized pipe\n");
+ return;
+ }
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+ *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
+ *(cmd++) = 0;
+ dbri_cmdsend(dbri, cmd);
+
+ desc = dbri->pipes[pipe].first_desc;
+ while (desc != -1) {
+ dbri->descs[desc].inuse = 0;
+ desc = dbri->descs[desc].next;
+ }
+
+ dbri->pipes[pipe].desc = -1;
+ dbri->pipes[pipe].first_desc = -1;
+}
+
+/* FIXME: direction as an argument? */
+static void setup_pipe(snd_dbri_t * dbri, int pipe, int sdp)
+{
+ if (pipe < 0 || pipe > 31) {
+ printk("DBRI: setup_pipe called with illegal pipe number\n");
+ return;
+ }
+
+ if ((sdp & 0xf800) != sdp) {
+ printk("DBRI: setup_pipe called with strange SDP value\n");
+ /* sdp &= 0xf800; */
+ }
+
+ /* If this is a fixed receive pipe, arrange for an interrupt
+ * every time its data changes
+ */
+ if (D_SDP_MODE(sdp) == D_SDP_FIXED && !(sdp & D_SDP_TO_SER))
+ sdp |= D_SDP_CHANGE;
+
+ sdp |= D_PIPE(pipe);
+ dbri->pipes[pipe].sdp = sdp;
+ dbri->pipes[pipe].desc = -1;
+ dbri->pipes[pipe].first_desc = -1;
+ if (sdp & D_SDP_TO_SER)
+ dbri->pipes[pipe].direction = PIPEoutput;
+ else
+ dbri->pipes[pipe].direction = PIPEinput;
+
+ reset_pipe(dbri, pipe);
+}
+
+/* FIXME: direction not needed */
+static void link_time_slot(snd_dbri_t * dbri, int pipe,
+ enum in_or_out direction, int basepipe,
+ int length, int cycle)
+{
+ volatile s32 *cmd;
+ int val;
+ int prevpipe;
+ int nextpipe;
+
+ if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
+ printk
+ ("DBRI: link_time_slot called with illegal pipe number\n");
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
+ printk("DBRI: link_time_slot called on uninitialized pipe\n");
+ return;
+ }
+
+ /* Deal with CHI special case:
+ * "If transmission on edges 0 or 1 is desired, then cycle n
+ * (where n = # of bit times per frame...) must be used."
+ * - DBRI data sheet, page 11
+ */
+ if (basepipe == 16 && direction == PIPEoutput && cycle == 0)
+ cycle = dbri->chi_bpf;
+
+ if (basepipe == pipe) {
+ prevpipe = pipe;
+ nextpipe = pipe;
+ } else {
+ /* We're not initializing a new linked list (basepipe != pipe),
+ * so run through the linked list and find where this pipe
+ * should be sloted in, based on its cycle. CHI confuses
+ * things a bit, since it has a single anchor for both its
+ * transmit and receive lists.
+ */
+ if (basepipe == 16) {
+ if (direction == PIPEinput) {
+ prevpipe = dbri->chi_in_pipe;
+ } else {
+ prevpipe = dbri->chi_out_pipe;
+ }
+ } else {
+ prevpipe = basepipe;
+ }
+
+ nextpipe = dbri->pipes[prevpipe].nextpipe;
+
+ while (dbri->pipes[nextpipe].cycle < cycle
+ && dbri->pipes[nextpipe].nextpipe != basepipe) {
+ prevpipe = nextpipe;
+ nextpipe = dbri->pipes[nextpipe].nextpipe;
+ }
+ }
+
+ if (prevpipe == 16) {
+ if (direction == PIPEinput) {
+ dbri->chi_in_pipe = pipe;
+ } else {
+ dbri->chi_out_pipe = pipe;
+ }
+ } else {
+ dbri->pipes[prevpipe].nextpipe = pipe;
+ }
+
+ dbri->pipes[pipe].nextpipe = nextpipe;
+ dbri->pipes[pipe].cycle = cycle;
+ dbri->pipes[pipe].length = length;
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+
+ if (direction == PIPEinput) {
+ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) =
+ D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ *(cmd++) = 0;
+ } else {
+ val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) =
+ D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+ }
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+static void unlink_time_slot(snd_dbri_t * dbri, int pipe,
+ enum in_or_out direction, int prevpipe,
+ int nextpipe)
+{
+ volatile s32 *cmd;
+ int val;
+
+ if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
+ printk
+ ("DBRI: unlink_time_slot called with illegal pipe number\n");
+ return;
+ }
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+
+ if (direction == PIPEinput) {
+ val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = D_TS_NEXT(nextpipe);
+ *(cmd++) = 0;
+ } else {
+ val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_NEXT(nextpipe);
+ }
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+/* xmit_fixed() / recv_fixed()
+ *
+ * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
+ * expected to change much, and which we don't need to buffer.
+ * The DBRI only interrupts us when the data changes (receive pipes),
+ * or only changes the data when this function is called (transmit pipes).
+ * Only short pipes (numbers 16-31) can be used in fixed data mode.
+ *
+ * These function operate on a 32-bit field, no matter how large
+ * the actual time slot is. The interrupt handler takes care of bit
+ * ordering and alignment. An 8-bit time slot will always end up
+ * in the low-order 8 bits, filled either MSB-first or LSB-first,
+ * depending on the settings passed to setup_pipe()
+ */
+static void xmit_fixed(snd_dbri_t * dbri, int pipe, unsigned int data)
+{
+ volatile s32 *cmd;
+
+ if (pipe < 16 || pipe > 31) {
+ printk("DBRI: xmit_fixed: Illegal pipe number\n");
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {
+ printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe);
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
+ printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);
+ return;
+ }
+
+ if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) {
+ printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe);
+ return;
+ }
+
+ /* DBRI short pipes always transmit LSB first */
+
+ if (dbri->pipes[pipe].sdp & D_SDP_MSB)
+ data = reverse_bytes(data, dbri->pipes[pipe].length);
+
+ cmd = dbri_cmdlock(dbri, GetLock);
+
+ *(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
+ *(cmd++) = data;
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+static void recv_fixed(snd_dbri_t * dbri, int pipe, volatile __u32 * ptr)
+{
+ if (pipe < 16 || pipe > 31) {
+ printk("DBRI: recv_fixed called with illegal pipe number\n");
+ return;
+ }
+
+ if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
+ printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe);
+ return;
+ }
+
+ if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
+ printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe);
+ return;
+ }
+
+ dbri->pipes[pipe].recv_fixed_ptr = ptr;
+}
+
+/* setup_descs()
+ *
+ * Setup transmit/receive data on a "long" pipe - i.e, one associated
+ * with a DMA buffer.
+ *
+ * Only pipe numbers 0-15 can be used in this mode.
+ *
+ * This function takes a stream number pointing to a data buffer,
+ * and work by building chains of descriptors which identify the
+ * data buffers. Buffers too large for a single descriptor will
+ * be spread across multiple descriptors.
+ */
+static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period)
+{
+ dbri_streaminfo_t *info = &dbri->stream_info[streamno];
+ __u32 dvma_buffer;
+ int desc = 0;
+ int len;
+ int first_desc = -1;
+ int last_desc = -1;
+
+ if (info->pipe < 0 || info->pipe > 15) {
+ printk("DBRI: setup_descs: Illegal pipe number\n");
+ return -2;
+ }
+
+ if (dbri->pipes[info->pipe].sdp == 0) {
+ printk("DBRI: setup_descs: Uninitialized pipe %d\n",
+ info->pipe);
+ return -2;
+ }
+
+ dvma_buffer = info->dvma_buffer;
+ len = info->size;
+
+ if (streamno == DBRI_PLAY) {
+ if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) {
+ printk("DBRI: setup_descs: Called on receive pipe %d\n",
+ info->pipe);
+ return -2;
+ }
+ } else {
+ if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) {
+ printk
+ ("DBRI: setup_descs: Called on transmit pipe %d\n",
+ info->pipe);
+ return -2;
+ }
+ /* Should be able to queue multiple buffers to receive on a pipe */
+ if (pipe_active(dbri, info->pipe)) {
+ printk("DBRI: recv_on_pipe: Called on active pipe %d\n",
+ info->pipe);
+ return -2;
+ }
+
+ /* Make sure buffer size is multiple of four */
+ len &= ~3;
+ }
+
+ while (len > 0) {
+ int mylen;
+
+ for (; desc < DBRI_NO_DESCS; desc++) {
+ if (!dbri->descs[desc].inuse)
+ break;
+ }
+ if (desc == DBRI_NO_DESCS) {
+ printk("DBRI: setup_descs: No descriptors\n");
+ return -1;
+ }
+
+ if (len > DBRI_TD_MAXCNT) {
+ mylen = DBRI_TD_MAXCNT; /* 8KB - 1 */
+ } else {
+ mylen = len;
+ }
+ if (mylen > period) {
+ mylen = period;
+ }
+
+ dbri->descs[desc].inuse = 1;
+ dbri->descs[desc].next = -1;
+ dbri->dma->desc[desc].ba = dvma_buffer;
+ dbri->dma->desc[desc].nda = 0;
+
+ if (streamno == DBRI_PLAY) {
+ dbri->descs[desc].len = mylen;
+ dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);
+ dbri->dma->desc[desc].word4 = 0;
+ if (first_desc != -1)
+ dbri->dma->desc[desc].word1 |= DBRI_TD_M;
+ } else {
+ dbri->descs[desc].len = 0;
+ dbri->dma->desc[desc].word1 = 0;
+ dbri->dma->desc[desc].word4 =
+ DBRI_RD_B | DBRI_RD_BCNT(mylen);
+ }
+
+ if (first_desc == -1) {
+ first_desc = desc;
+ } else {
+ dbri->descs[last_desc].next = desc;
+ dbri->dma->desc[last_desc].nda =
+ dbri->dma_dvma + dbri_dma_off(desc, desc);
+ }
+
+ last_desc = desc;
+ dvma_buffer += mylen;
+ len -= mylen;
+ }
+
+ if (first_desc == -1 || last_desc == -1) {
+ printk("DBRI: setup_descs: Not enough descriptors available\n");
+ return -1;
+ }
+
+ dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M;
+ if (streamno == DBRI_PLAY) {
+ dbri->dma->desc[last_desc].word1 |=
+ DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
+ }
+ dbri->pipes[info->pipe].first_desc = first_desc;
+ dbri->pipes[info->pipe].desc = first_desc;
+
+ for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) {
+ dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",
+ desc,
+ dbri->dma->desc[desc].word1,
+ dbri->dma->desc[desc].ba,
+ dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4);
+ }
+ return 0;
+}
+
+/*
+****************************************************************************
+************************** DBRI - CHI interface ****************************
+****************************************************************************
+
+The CHI is a four-wire (clock, frame sync, data in, data out) time-division
+multiplexed serial interface which the DBRI can operate in either master
+(give clock/frame sync) or slave (take clock/frame sync) mode.
+
+*/
+
+enum master_or_slave { CHImaster, CHIslave };
+
+static void reset_chi(snd_dbri_t * dbri, enum master_or_slave master_or_slave,
+ int bits_per_frame)
+{
+ volatile s32 *cmd;
+ int val;
+ static int chi_initialized = 0; /* FIXME: mutex? */
+
+ if (!chi_initialized) {
+
+ cmd = dbri_cmdlock(dbri, GetLock);
+
+ /* Set CHI Anchor: Pipe 16 */
+
+ val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+ *(cmd++) = 0;
+
+ val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
+ *(cmd++) = DBRI_CMD(D_DTS, 0, val);
+ *(cmd++) = 0;
+ *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
+
+ dbri->pipes[16].sdp = 1;
+ dbri->pipes[16].nextpipe = 16;
+ dbri->chi_in_pipe = 16;
+ dbri->chi_out_pipe = 16;
+
+#if 0
+ chi_initialized++;
+#endif
+ } else {
+ int pipe;
+
+ for (pipe = dbri->chi_in_pipe;
+ pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
+ unlink_time_slot(dbri, pipe, PIPEinput,
+ 16, dbri->pipes[pipe].nextpipe);
+ }
+ for (pipe = dbri->chi_out_pipe;
+ pipe != 16; pipe = dbri->pipes[pipe].nextpipe) {
+ unlink_time_slot(dbri, pipe, PIPEoutput,
+ 16, dbri->pipes[pipe].nextpipe);
+ }
+
+ dbri->chi_in_pipe = 16;
+ dbri->chi_out_pipe = 16;
+
+ cmd = dbri_cmdlock(dbri, GetLock);
+ }
+
+ if (master_or_slave == CHIslave) {
+ /* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
+ *
+ * CHICM = 0 (slave mode, 8 kHz frame rate)
+ * IR = give immediate CHI status interrupt
+ * EN = give CHI status interrupt upon change
+ */
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
+ } else {
+ /* Setup DBRI for CHI Master - generate clock, FS
+ *
+ * BPF = bits per 8 kHz frame
+ * 12.288 MHz / CHICM_divisor = clock rate
+ * FD = 1 - drive CHIFS on rising edge of CHICK
+ */
+ int clockrate = bits_per_frame * 8;
+ int divisor = 12288 / clockrate;
+
+ if (divisor > 255 || divisor * clockrate != 12288)
+ printk("DBRI: illegal bits_per_frame in setup_chi\n");
+
+ *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
+ | D_CHI_BPF(bits_per_frame));
+ }
+
+ dbri->chi_bpf = bits_per_frame;
+
+ /* CHI Data Mode
+ *
+ * RCE = 0 - receive on falling edge of CHICK
+ * XCE = 1 - transmit on rising edge of CHICK
+ * XEN = 1 - enable transmitter
+ * REN = 1 - enable receiver
+ */
+
+ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+ *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN);
+
+ dbri_cmdsend(dbri, cmd);
+}
+
+/*
+****************************************************************************
+*********************** CS4215 audio codec management **********************
+****************************************************************************
+
+In the standard SPARC audio configuration, the CS4215 codec is attached
+to the DBRI via the CHI interface and few of the DBRI's PIO pins.
+
+*/
+static void cs4215_setup_pipes(snd_dbri_t * dbri)
+{
+ /*
+ * Data mode:
+ * Pipe 4: Send timeslots 1-4 (audio data)
+ * Pipe 20: Send timeslots 5-8 (part of ctrl data)
+ * Pipe 6: Receive timeslots 1-4 (audio data)
+ * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
+ * interrupt, and the rest of the data (slot 5 and 8) is
+ * not relevant for us (only for doublechecking).
+ *
+ * Control mode:
+ * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
+ * Pipe 18: Receive timeslot 1 (clb).
+ * Pipe 19: Receive timeslot 7 (version).
+ */
+
+ setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+
+ setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
+ setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+ setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
+}
+
+static int cs4215_init_data(struct cs4215 *mm)
+{
+ /*
+ * No action, memory resetting only.
+ *
+ * Data Time Slot 5-8
+ * Speaker,Line and Headphone enable. Gain set to the half.
+ * Input is mike.
+ */
+ mm->data[0] = CS4215_LO(0x20) | CS4215_HE | CS4215_LE;
+ mm->data[1] = CS4215_RO(0x20) | CS4215_SE;
+ mm->data[2] = CS4215_LG(0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;
+ mm->data[3] = CS4215_RG(0x8) | CS4215_MA(0xf);
+
+ /*
+ * Control Time Slot 1-4
+ * 0: Default I/O voltage scale
+ * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled
+ * 2: Serial enable, CHI master, 128 bits per frame, clock 1
+ * 3: Tests disabled
+ */
+ mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;
+ mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
+ mm->ctrl[2] = CS4215_XCLK | CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
+ mm->ctrl[3] = 0;
+
+ mm->status = 0;
+ mm->version = 0xff;
+ mm->precision = 8; /* For ULAW */
+ mm->channels = 2;
+
+ return 0;
+}
+
+static void cs4215_setdata(snd_dbri_t * dbri, int muted)
+{
+ if (muted) {
+ dbri->mm.data[0] |= 63;
+ dbri->mm.data[1] |= 63;
+ dbri->mm.data[2] &= ~15;
+ dbri->mm.data[3] &= ~15;
+ } else {
+ /* Start by setting the playback attenuation. */
+ dbri_streaminfo_t *info = &dbri->stream_info[DBRI_PLAY];
+ int left_gain = info->left_gain % 64;
+ int right_gain = info->right_gain % 64;
+
+ if (info->balance < DBRI_MID_BALANCE) {
+ right_gain *= info->balance;
+ right_gain /= DBRI_MID_BALANCE;
+ } else {
+ left_gain *= DBRI_RIGHT_BALANCE - info->balance;
+ left_gain /= DBRI_MID_BALANCE;
+ }
+
+ dbri->mm.data[0] &= ~0x3f; /* Reset the volume bits */
+ dbri->mm.data[1] &= ~0x3f;
+ dbri->mm.data[0] |= (DBRI_MAX_VOLUME - left_gain);
+ dbri->mm.data[1] |= (DBRI_MAX_VOLUME - right_gain);
+
+ /* Now set the recording gain. */
+ info = &dbri->stream_info[DBRI_REC];
+ left_gain = info->left_gain % 16;
+ right_gain = info->right_gain % 16;
+ dbri->mm.data[2] |= CS4215_LG(left_gain);
+ dbri->mm.data[3] |= CS4215_RG(right_gain);
+ }
+
+ xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
+}
+
+/*
+ * Set the CS4215 to data mode.
+ */
+static void cs4215_open(snd_dbri_t * dbri)
+{
+ int data_width;
+ u32 tmp;
+
+ dprintk(D_MM, "cs4215_open: %d channels, %d bits\n",
+ dbri->mm.channels, dbri->mm.precision);
+
+ /* Temporarily mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+
+ /*
+ * Data mode:
+ * Pipe 4: Send timeslots 1-4 (audio data)
+ * Pipe 20: Send timeslots 5-8 (part of ctrl data)
+ * Pipe 6: Receive timeslots 1-4 (audio data)
+ * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
+ * interrupt, and the rest of the data (slot 5 and 8) is
+ * not relevant for us (only for doublechecking).
+ *
+ * Just like in control mode, the time slots are all offset by eight
+ * bits. The CS4215, it seems, observes TSIN (the delayed signal)
+ * even if it's the CHI master. Don't ask me...
+ */
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~(D_C); /* Disable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+
+ /* Switch CS4215 to data mode - set PIO3 to 1 */
+ sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 |
+ (dbri->mm.onboard ? D_PIO0 : D_PIO2), dbri->regs + REG2);
+
+ reset_chi(dbri, CHIslave, 128);
+
+ /* Note: this next doesn't work for 8-bit stereo, because the two
+ * channels would be on timeslots 1 and 3, with 2 and 4 idle.
+ * (See CS4215 datasheet Fig 15)
+ *
+ * DBRI non-contiguous mode would be required to make this work.
+ */
+ data_width = dbri->mm.channels * dbri->mm.precision;
+
+ link_time_slot(dbri, 20, PIPEoutput, 16, 32, dbri->mm.offset + 32);
+ link_time_slot(dbri, 4, PIPEoutput, 16, data_width, dbri->mm.offset);
+ link_time_slot(dbri, 6, PIPEinput, 16, data_width, dbri->mm.offset);
+ link_time_slot(dbri, 21, PIPEinput, 16, 16, dbri->mm.offset + 40);
+
+ /* FIXME: enable CHI after _setdata? */
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp |= D_C; /* Enable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+
+ cs4215_setdata(dbri, 0);
+}
+
+/*
+ * Send the control information (i.e. audio format)
+ */
+static int cs4215_setctrl(snd_dbri_t * dbri)
+{
+ int i, val;
+ u32 tmp;
+
+ /* FIXME - let the CPU do something useful during these delays */
+
+ /* Temporarily mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+
+ /*
+ * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
+ * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
+ */
+ val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2);
+ sbus_writel(val, dbri->regs + REG2);
+ dprintk(D_MM, "cs4215_setctrl: reg2=0x%x\n", val);
+ udelay(34);
+
+ /* In Control mode, the CS4215 is a slave device, so the DBRI must
+ * operate as CHI master, supplying clocking and frame synchronization.
+ *
+ * In Data mode, however, the CS4215 must be CHI master to insure
+ * that its data stream is synchronous with its codec.
+ *
+ * The upshot of all this? We start by putting the DBRI into master
+ * mode, program the CS4215 in Control mode, then switch the CS4215
+ * into Data mode and put the DBRI into slave mode. Various timing
+ * requirements must be observed along the way.
+ *
+ * Oh, and one more thing, on a SPARCStation 20 (and maybe
+ * others?), the addressing of the CS4215's time slots is
+ * offset by eight bits, so we add eight to all the "cycle"
+ * values in the Define Time Slot (DTS) commands. This is
+ * done in hardware by a TI 248 that delays the DBRI->4215
+ * frame sync signal by eight clock cycles. Anybody know why?
+ */
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~D_C; /* Disable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+
+ reset_chi(dbri, CHImaster, 128);
+
+ /*
+ * Control mode:
+ * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
+ * Pipe 18: Receive timeslot 1 (clb).
+ * Pipe 19: Receive timeslot 7 (version).
+ */
+
+ link_time_slot(dbri, 17, PIPEoutput, 16, 32, dbri->mm.offset);
+ link_time_slot(dbri, 18, PIPEinput, 16, 8, dbri->mm.offset);
+ link_time_slot(dbri, 19, PIPEinput, 16, 8, dbri->mm.offset + 48);
+
+ /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
+ dbri->mm.ctrl[0] &= ~CS4215_CLB;
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
+
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp |= D_C; /* Enable CHI */
+ sbus_writel(tmp, dbri->regs + REG0);
+
+ for (i = 64; ((dbri->mm.status & 0xe4) != 0x20); --i) {
+ udelay(125);
+ }
+ if (i == 0) {
+ dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n",
+ dbri->mm.status);
+ return -1;
+ }
+
+ /* Disable changes to our copy of the version number, as we are about
+ * to leave control mode.
+ */
+ recv_fixed(dbri, 19, NULL);
+
+ /* Terminate CS4215 control mode - data sheet says
+ * "Set CLB=1 and send two more frames of valid control info"
+ */
+ dbri->mm.ctrl[0] |= CS4215_CLB;
+ xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
+
+ /* Two frames of control info @ 8kHz frame rate = 250 us delay */
+ udelay(250);
+
+ cs4215_setdata(dbri, 0);
+
+ return 0;
+}
+
+/*
+ * Setup the codec with the sampling rate, audio format and number of
+ * channels.
+ * As part of the process we resend the settings for the data
+ * timeslots as well.
+ */
+static int cs4215_prepare(snd_dbri_t * dbri, unsigned int rate,
+ snd_pcm_format_t format, unsigned int channels)
+{
+ int freq_idx;
+ int ret = 0;
+
+ /* Lookup index for this rate */
+ for (freq_idx = 0; CS4215_FREQ[freq_idx].freq != 0; freq_idx++) {
+ if (CS4215_FREQ[freq_idx].freq == rate)
+ break;
+ }
+ if (CS4215_FREQ[freq_idx].freq != rate) {
+ printk(KERN_WARNING "DBRI: Unsupported rate %d Hz\n", rate);
+ return -1;
+ }
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_MU_LAW:
+ dbri->mm.ctrl[1] = CS4215_DFR_ULAW;
+ dbri->mm.precision = 8;
+ break;
+ case SNDRV_PCM_FORMAT_A_LAW:
+ dbri->mm.ctrl[1] = CS4215_DFR_ALAW;
+ dbri->mm.precision = 8;
+ break;
+ case SNDRV_PCM_FORMAT_U8:
+ dbri->mm.ctrl[1] = CS4215_DFR_LINEAR8;
+ dbri->mm.precision = 8;
+ break;
+ case SNDRV_PCM_FORMAT_S16_BE:
+ dbri->mm.ctrl[1] = CS4215_DFR_LINEAR16;
+ dbri->mm.precision = 16;
+ break;
+ default:
+ printk(KERN_WARNING "DBRI: Unsupported format %d\n", format);
+ return -1;
+ }
+
+ /* Add rate parameters */
+ dbri->mm.ctrl[1] |= CS4215_FREQ[freq_idx].csval;
+ dbri->mm.ctrl[2] = CS4215_XCLK |
+ CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal;
+
+ dbri->mm.channels = channels;
+ /* Stereo bit: 8 bit stereo not working yet. */
+ if ((channels > 1) && (dbri->mm.precision == 16))
+ dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
+
+ ret = cs4215_setctrl(dbri);
+ if (ret == 0)
+ cs4215_open(dbri); /* set codec to data mode */
+
+ return ret;
+}
+
+/*
+ *
+ */
+static int cs4215_init(snd_dbri_t * dbri)
+{
+ u32 reg2 = sbus_readl(dbri->regs + REG2);
+ dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2);
+
+ /* Look for the cs4215 chips */
+ if (reg2 & D_PIO2) {
+ dprintk(D_MM, "Onboard CS4215 detected\n");
+ dbri->mm.onboard = 1;
+ }
+ if (reg2 & D_PIO0) {
+ dprintk(D_MM, "Speakerbox detected\n");
+ dbri->mm.onboard = 0;
+
+ if (reg2 & D_PIO2) {
+ printk(KERN_INFO "DBRI: Using speakerbox / "
+ "ignoring onboard mmcodec.\n");
+ sbus_writel(D_ENPIO2, dbri->regs + REG2);
+ }
+ }
+
+ if (!(reg2 & (D_PIO0 | D_PIO2))) {
+ printk(KERN_ERR "DBRI: no mmcodec found.\n");
+ return -EIO;
+ }
+
+ cs4215_setup_pipes(dbri);
+
+ cs4215_init_data(&dbri->mm);
+
+ /* Enable capture of the status & version timeslots. */
+ recv_fixed(dbri, 18, &dbri->mm.status);
+ recv_fixed(dbri, 19, &dbri->mm.version);
+
+ dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
+ if (cs4215_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
+ dprintk(D_MM, "CS4215 failed probe at offset %d\n",
+ dbri->mm.offset);
+ return -EIO;
+ }
+ dprintk(D_MM, "Found CS4215 at offset %d\n", dbri->mm.offset);
+
+ return 0;
+}
+
+/*
+****************************************************************************
+*************************** DBRI interrupt handler *************************
+****************************************************************************
+
+The DBRI communicates with the CPU mainly via a circular interrupt
+buffer. When an interrupt is signaled, the CPU walks through the
+buffer and calls dbri_process_one_interrupt() for each interrupt word.
+Complicated interrupts are handled by dedicated functions (which
+appear first in this file). Any pending interrupts can be serviced by
+calling dbri_process_interrupt_buffer(), which works even if the CPU's
+interrupts are disabled. This function is used by dbri_cmdsend()
+to make sure we're synced up with the chip after each command sequence,
+even if we're running cli'ed.
+
+*/
+
+/* xmit_descs()
+ *
+ * Transmit the current TD's for recording/playing, if needed.
+ * For playback, ALSA has filled the DMA memory with new data (we hope).
+ */
+static void xmit_descs(unsigned long data)
+{
+ snd_dbri_t *dbri = (snd_dbri_t *) data;
+ dbri_streaminfo_t *info;
+ volatile s32 *cmd;
+ unsigned long flags;
+ int first_td;
+
+ if (dbri == NULL)
+ return; /* Disabled */
+
+ /* First check the recording stream for buffer overflow */
+ info = &dbri->stream_info[DBRI_REC];
+ spin_lock_irqsave(&dbri->lock, flags);
+
+ if ((info->left >= info->size) && (info->pipe >= 0)) {
+ first_td = dbri->pipes[info->pipe].first_desc;
+
+ dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td);
+
+ /* Stream could be closed by the time we run. */
+ if (first_td < 0) {
+ goto play;
+ }
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+ *(cmd++) = DBRI_CMD(D_SDP, 0,
+ dbri->pipes[info->pipe].sdp
+ | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
+ dbri_cmdsend(dbri, cmd);
+
+ /* Reset our admin of the pipe & bytes read. */
+ dbri->pipes[info->pipe].desc = first_td;
+ info->left = 0;
+ }
+
+play:
+ spin_unlock_irqrestore(&dbri->lock, flags);
+
+ /* Now check the playback stream for buffer underflow */
+ info = &dbri->stream_info[DBRI_PLAY];
+ spin_lock_irqsave(&dbri->lock, flags);
+
+ if ((info->left <= 0) && (info->pipe >= 0)) {
+ first_td = dbri->pipes[info->pipe].first_desc;
+
+ dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td);
+
+ /* Stream could be closed by the time we run. */
+ if (first_td < 0) {
+ spin_unlock_irqrestore(&dbri->lock, flags);
+ return;
+ }
+
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+ *(cmd++) = DBRI_CMD(D_SDP, 0,
+ dbri->pipes[info->pipe].sdp
+ | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
+ dbri_cmdsend(dbri, cmd);
+
+ /* Reset our admin of the pipe & bytes written. */
+ dbri->pipes[info->pipe].desc = first_td;
+ info->left = info->size;
+ }
+ spin_unlock_irqrestore(&dbri->lock, flags);
+}
+
+DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0);
+
+/* transmission_complete_intr()
+ *
+ * Called by main interrupt handler when DBRI signals transmission complete
+ * on a pipe (interrupt triggered by the B bit in a transmit descriptor).
+ *
+ * Walks through the pipe's list of transmit buffer descriptors, releasing
+ * each one's DMA buffer (if present), flagging the descriptor available,
+ * and signaling its callback routine (if present), before proceeding
+ * to the next one. Stops when the first descriptor is found without
+ * TBC (Transmit Buffer Complete) set, or we've run through them all.
+ */
+
+static void transmission_complete_intr(snd_dbri_t * dbri, int pipe)
+{
+ dbri_streaminfo_t *info;
+ int td;
+ int status;
+
+ info = &dbri->stream_info[DBRI_PLAY];
+
+ td = dbri->pipes[pipe].desc;
+ while (td >= 0) {
+ if (td >= DBRI_NO_DESCS) {
+ printk(KERN_ERR "DBRI: invalid td on pipe %d\n", pipe);
+ return;
+ }
+
+ status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);
+ if (!(status & DBRI_TD_TBC)) {
+ break;
+ }
+
+ dprintk(D_INT, "TD %d, status 0x%02x\n", td, status);
+
+ dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */
+ info->offset += dbri->descs[td].len;
+ info->left -= dbri->descs[td].len;
+
+ /* On the last TD, transmit them all again. */
+ if (dbri->descs[td].next == -1) {
+ if (info->left > 0) {
+ printk(KERN_WARNING
+ "%d bytes left after last transfer.\n",
+ info->left);
+ info->left = 0;
+ }
+ tasklet_schedule(&xmit_descs_task);
+ }
+
+ td = dbri->descs[td].next;
+ dbri->pipes[pipe].desc = td;
+ }
+
+ /* Notify ALSA */
+ if (spin_is_locked(&dbri->lock)) {
+ spin_unlock(&dbri->lock);
+ snd_pcm_period_elapsed(info->substream);
+ spin_lock(&dbri->lock);
+ } else
+ snd_pcm_period_elapsed(info->substream);
+}
+
+static void reception_complete_intr(snd_dbri_t * dbri, int pipe)
+{
+ dbri_streaminfo_t *info;
+ int rd = dbri->pipes[pipe].desc;
+ s32 status;
+
+ if (rd < 0 || rd >= DBRI_NO_DESCS) {
+ printk(KERN_ERR "DBRI: invalid rd on pipe %d\n", pipe);
+ return;
+ }
+
+ dbri->descs[rd].inuse = 0;
+ dbri->pipes[pipe].desc = dbri->descs[rd].next;
+ status = dbri->dma->desc[rd].word1;
+ dbri->dma->desc[rd].word1 = 0; /* Reset it for next time. */
+
+ info = &dbri->stream_info[DBRI_REC];
+ info->offset += DBRI_RD_CNT(status);
+ info->left += DBRI_RD_CNT(status);
+
+ /* FIXME: Check status */
+
+ dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n",
+ rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
+
+ /* On the last TD, transmit them all again. */
+ if (dbri->descs[rd].next == -1) {
+ if (info->left > info->size) {
+ printk(KERN_WARNING
+ "%d bytes recorded in %d size buffer.\n",
+ info->left, info->size);
+ }
+ tasklet_schedule(&xmit_descs_task);
+ }
+
+ /* Notify ALSA */
+ if (spin_is_locked(&dbri->lock)) {
+ spin_unlock(&dbri->lock);
+ snd_pcm_period_elapsed(info->substream);
+ spin_lock(&dbri->lock);
+ } else
+ snd_pcm_period_elapsed(info->substream);
+}
+
+static void dbri_process_one_interrupt(snd_dbri_t * dbri, int x)
+{
+ int val = D_INTR_GETVAL(x);
+ int channel = D_INTR_GETCHAN(x);
+ int command = D_INTR_GETCMD(x);
+ int code = D_INTR_GETCODE(x);
+#ifdef DBRI_DEBUG
+ int rval = D_INTR_GETRVAL(x);
+#endif
+
+ if (channel == D_INTR_CMD) {
+ dprintk(D_CMD, "INTR: Command: %-5s Value:%d\n",
+ cmds[command], val);
+ } else {
+ dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",
+ channel, code, rval);
+ }
+
+ if (channel == D_INTR_CMD && command == D_WAIT) {
+ dbri->wait_seen++;
+ return;
+ }
+
+ switch (code) {
+ case D_INTR_BRDY:
+ reception_complete_intr(dbri, channel);
+ break;
+ case D_INTR_XCMP:
+ case D_INTR_MINT:
+ transmission_complete_intr(dbri, channel);
+ break;
+ case D_INTR_UNDR:
+ /* UNDR - Transmission underrun
+ * resend SDP command with clear pipe bit (C) set
+ */
+ {
+ volatile s32 *cmd;
+
+ int pipe = channel;
+ int td = dbri->pipes[pipe].desc;
+
+ dbri->dma->desc[td].word4 = 0;
+ cmd = dbri_cmdlock(dbri, NoGetLock);
+ *(cmd++) = DBRI_CMD(D_SDP, 0,
+ dbri->pipes[pipe].sdp
+ | D_SDP_P | D_SDP_C | D_SDP_2SAME);
+ *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);
+ dbri_cmdsend(dbri, cmd);
+ }
+ break;
+ case D_INTR_FXDT:
+ /* FXDT - Fixed data change */
+ if (dbri->pipes[channel].sdp & D_SDP_MSB)
+ val = reverse_bytes(val, dbri->pipes[channel].length);
+
+ if (dbri->pipes[channel].recv_fixed_ptr)
+ *(dbri->pipes[channel].recv_fixed_ptr) = val;
+ break;
+ default:
+ if (channel != D_INTR_CMD)
+ printk(KERN_WARNING
+ "DBRI: Ignored Interrupt: %d (0x%x)\n", code, x);
+ }
+}
+
+/* dbri_process_interrupt_buffer advances through the DBRI's interrupt
+ * buffer until it finds a zero word (indicating nothing more to do
+ * right now). Non-zero words require processing and are handed off
+ * to dbri_process_one_interrupt AFTER advancing the pointer. This
+ * order is important since we might recurse back into this function
+ * and need to make sure the pointer has been advanced first.
+ */
+static void dbri_process_interrupt_buffer(snd_dbri_t * dbri)
+{
+ s32 x;
+
+ while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
+ dbri->dma->intr[dbri->dbri_irqp] = 0;
+ dbri->dbri_irqp++;
+ if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
+ dbri->dbri_irqp = 1;
+ else if ((dbri->dbri_irqp & (DBRI_INT_BLK - 1)) == 0)
+ dbri->dbri_irqp++;
+
+ dbri_process_one_interrupt(dbri, x);
+ }
+}
+
+static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ snd_dbri_t *dbri = dev_id;
+ static int errcnt = 0;
+ int x;
+
+ if (dbri == NULL)
+ return IRQ_NONE;
+ spin_lock(&dbri->lock);
+
+ /*
+ * Read it, so the interrupt goes away.
+ */
+ x = sbus_readl(dbri->regs + REG1);
+
+ if (x & (D_MRR | D_MLE | D_LBG | D_MBE)) {
+ u32 tmp;
+
+ if (x & D_MRR)
+ printk(KERN_ERR
+ "DBRI: Multiple Error Ack on SBus reg1=0x%x\n",
+ x);
+ if (x & D_MLE)
+ printk(KERN_ERR
+ "DBRI: Multiple Late Error on SBus reg1=0x%x\n",
+ x);
+ if (x & D_LBG)
+ printk(KERN_ERR
+ "DBRI: Lost Bus Grant on SBus reg1=0x%x\n", x);
+ if (x & D_MBE)
+ printk(KERN_ERR
+ "DBRI: Burst Error on SBus reg1=0x%x\n", x);
+
+ /* Some of these SBus errors cause the chip's SBus circuitry
+ * to be disabled, so just re-enable and try to keep going.
+ *
+ * The only one I've seen is MRR, which will be triggered
+ * if you let a transmit pipe underrun, then try to CDP it.
+ *
+ * If these things persist, we should probably reset
+ * and re-init the chip.
+ */
+ if ((++errcnt) % 10 == 0) {
+ dprintk(D_INT, "Interrupt errors exceeded.\n");
+ dbri_reset(dbri);
+ } else {
+ tmp = sbus_readl(dbri->regs + REG0);
+ tmp &= ~(D_D);
+ sbus_writel(tmp, dbri->regs + REG0);
+ }
+ }
+
+ dbri_process_interrupt_buffer(dbri);
+
+ /* FIXME: Write 0 into regs to ACK interrupt */
+
+ spin_unlock(&dbri->lock);
+
+ return IRQ_HANDLED;
+}
+
+/****************************************************************************
+ PCM Interface
+****************************************************************************/
+static snd_pcm_hardware_t snd_dbri_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_MU_LAW |
+ SNDRV_PCM_FMTBIT_A_LAW |
+ SNDRV_PCM_FMTBIT_U8 |
+ SNDRV_PCM_FMTBIT_S16_BE,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = (64 * 1024),
+ .period_bytes_min = 1,
+ .period_bytes_max = DBRI_TD_MAXCNT,
+ .periods_min = 1,
+ .periods_max = 1024,
+};
+
+static int snd_dbri_open(snd_pcm_substream_t * substream)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ unsigned long flags;
+
+ dprintk(D_USR, "open audio output.\n");
+ runtime->hw = snd_dbri_pcm_hw;
+
+ spin_lock_irqsave(&dbri->lock, flags);
+ info->substream = substream;
+ info->left = 0;
+ info->offset = 0;
+ info->dvma_buffer = 0;
+ info->pipe = -1;
+ spin_unlock_irqrestore(&dbri->lock, flags);
+
+ cs4215_open(dbri);
+
+ return 0;
+}
+
+static int snd_dbri_close(snd_pcm_substream_t * substream)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+
+ dprintk(D_USR, "close audio output.\n");
+ info->substream = NULL;
+ info->left = 0;
+ info->offset = 0;
+
+ return 0;
+}
+
+static int snd_dbri_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ int direction;
+ int ret;
+
+ /* set sampling rate, audio format and number of channels */
+ ret = cs4215_prepare(dbri, params_rate(hw_params),
+ params_format(hw_params),
+ params_channels(hw_params));
+ if (ret != 0)
+ return ret;
+
+ if ((ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params))) < 0) {
+ snd_printk(KERN_ERR "malloc_pages failed with %d\n", ret);
+ return ret;
+ }
+
+ /* hw_params can get called multiple times. Only map the DMA once.
+ */
+ if (info->dvma_buffer == 0) {
+ if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+ direction = SBUS_DMA_TODEVICE;
+ else
+ direction = SBUS_DMA_FROMDEVICE;
+
+ info->dvma_buffer = sbus_map_single(dbri->sdev,
+ runtime->dma_area,
+ params_buffer_bytes(hw_params),
+ direction);
+ }
+
+ direction = params_buffer_bytes(hw_params);
+ dprintk(D_USR, "hw_params: %d bytes, dvma=%x\n",
+ direction, info->dvma_buffer);
+ return 0;
+}
+
+static int snd_dbri_hw_free(snd_pcm_substream_t * substream)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ int direction;
+ dprintk(D_USR, "hw_free.\n");
+
+ /* hw_free can get called multiple times. Only unmap the DMA once.
+ */
+ if (info->dvma_buffer) {
+ if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+ direction = SBUS_DMA_TODEVICE;
+ else
+ direction = SBUS_DMA_FROMDEVICE;
+
+ sbus_unmap_single(dbri->sdev, info->dvma_buffer,
+ substream->runtime->buffer_size, direction);
+ info->dvma_buffer = 0;
+ }
+ info->pipe = -1;
+
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_dbri_prepare(snd_pcm_substream_t * substream)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int ret;
+
+ info->size = snd_pcm_lib_buffer_bytes(substream);
+ if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+ info->pipe = 4; /* Send pipe */
+ else {
+ info->pipe = 6; /* Receive pipe */
+ info->left = info->size; /* To trigger submittal */
+ }
+
+ spin_lock_irq(&dbri->lock);
+
+ /* Setup the all the transmit/receive desciptors to cover the
+ * whole DMA buffer.
+ */
+ ret = setup_descs(dbri, DBRI_STREAMNO(substream),
+ snd_pcm_lib_period_bytes(substream));
+
+ runtime->stop_threshold = DBRI_TD_MAXCNT / runtime->channels;
+
+ spin_unlock_irq(&dbri->lock);
+
+ dprintk(D_USR, "prepare audio output. %d bytes\n", info->size);
+ return ret;
+}
+
+static int snd_dbri_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ dprintk(D_USR, "start audio, period is %d bytes\n",
+ (int)snd_pcm_lib_period_bytes(substream));
+ /* Enable & schedule the tasklet that re-submits the TDs. */
+ xmit_descs_task.data = (unsigned long)dbri;
+ tasklet_schedule(&xmit_descs_task);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ dprintk(D_USR, "stop audio.\n");
+ /* Make the tasklet bail out immediately. */
+ xmit_descs_task.data = 0;
+ reset_pipe(dbri, info->pipe);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t snd_dbri_pointer(snd_pcm_substream_t * substream)
+{
+ snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+ dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+ snd_pcm_uframes_t ret;
+
+ ret = bytes_to_frames(substream->runtime, info->offset)
+ % substream->runtime->buffer_size;
+ dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n",
+ ret, info->left);
+ return ret;
+}
+
+static snd_pcm_ops_t snd_dbri_ops = {
+ .open = snd_dbri_open,
+ .close = snd_dbri_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_dbri_hw_params,
+ .hw_free = snd_dbri_hw_free,
+ .prepare = snd_dbri_prepare,
+ .trigger = snd_dbri_trigger,
+ .pointer = snd_dbri_pointer,
+};
+
+static int __devinit snd_dbri_pcm(snd_dbri_t * dbri)
+{
+ snd_pcm_t *pcm;
+ int err;
+
+ if ((err = snd_pcm_new(dbri->card,
+ /* ID */ "sun_dbri",
+ /* device */ 0,
+ /* playback count */ 1,
+ /* capture count */ 1, &pcm)) < 0)
+ return err;
+ snd_assert(pcm != NULL, return -EINVAL);
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dbri_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
+
+ pcm->private_data = dbri;
+ pcm->info_flags = 0;
+ strcpy(pcm->name, dbri->card->shortname);
+ dbri->pcm = pcm;
+
+ if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ 64 * 1024, 64 * 1024)) < 0) {
+ return err;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ Mixer interface
+*****************************************************************************/
+
+static int snd_cs4215_info_volume(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ if (kcontrol->private_value == DBRI_PLAY) {
+ uinfo->value.integer.max = DBRI_MAX_VOLUME;
+ } else {
+ uinfo->value.integer.max = DBRI_MAX_GAIN;
+ }
+ return 0;
+}
+
+static int snd_cs4215_get_volume(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+ dbri_streaminfo_t *info;
+ snd_assert(dbri != NULL, return -EINVAL);
+ info = &dbri->stream_info[kcontrol->private_value];
+ snd_assert(info != NULL, return -EINVAL);
+
+ ucontrol->value.integer.value[0] = info->left_gain;
+ ucontrol->value.integer.value[1] = info->right_gain;
+ return 0;
+}
+
+static int snd_cs4215_put_volume(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+ dbri_streaminfo_t *info = &dbri->stream_info[kcontrol->private_value];
+ unsigned long flags;
+ int changed = 0;
+
+ if (info->left_gain != ucontrol->value.integer.value[0]) {
+ info->left_gain = ucontrol->value.integer.value[0];
+ changed = 1;
+ }
+ if (info->right_gain != ucontrol->value.integer.value[1]) {
+ info->right_gain = ucontrol->value.integer.value[1];
+ changed = 1;
+ }
+ if (changed == 1) {
+ /* First mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+ spin_lock_irqsave(&dbri->lock, flags);
+
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+ cs4215_setdata(dbri, 0);
+
+ spin_unlock_irqrestore(&dbri->lock, flags);
+ }
+ return changed;
+}
+
+static int snd_cs4215_info_single(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_info_t * uinfo)
+{
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+
+ uinfo->type = (mask == 1) ?
+ SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mask;
+ return 0;
+}
+
+static int snd_cs4215_get_single(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+ int elem = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0xff;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 1;
+ snd_assert(dbri != NULL, return -EINVAL);
+
+ if (elem < 4) {
+ ucontrol->value.integer.value[0] =
+ (dbri->mm.data[elem] >> shift) & mask;
+ } else {
+ ucontrol->value.integer.value[0] =
+ (dbri->mm.ctrl[elem - 4] >> shift) & mask;
+ }
+
+ if (invert == 1) {
+ ucontrol->value.integer.value[0] =
+ mask - ucontrol->value.integer.value[0];
+ }
+ return 0;
+}
+
+static int snd_cs4215_put_single(snd_kcontrol_t * kcontrol,
+ snd_ctl_elem_value_t * ucontrol)
+{
+ snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+ unsigned long flags;
+ int elem = kcontrol->private_value & 0xff;
+ int shift = (kcontrol->private_value >> 8) & 0xff;
+ int mask = (kcontrol->private_value >> 16) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & 1;
+ int changed = 0;
+ unsigned short val;
+ snd_assert(dbri != NULL, return -EINVAL);
+
+ val = (ucontrol->value.integer.value[0] & mask);
+ if (invert == 1)
+ val = mask - val;
+ val <<= shift;
+
+ if (elem < 4) {
+ dbri->mm.data[elem] = (dbri->mm.data[elem] &
+ ~(mask << shift)) | val;
+ changed = (val != dbri->mm.data[elem]);
+ } else {
+ dbri->mm.ctrl[elem - 4] = (dbri->mm.ctrl[elem - 4] &
+ ~(mask << shift)) | val;
+ changed = (val != dbri->mm.ctrl[elem - 4]);
+ }
+
+ dprintk(D_GEN, "put_single: mask=0x%x, changed=%d, "
+ "mixer-value=%ld, mm-value=0x%x\n",
+ mask, changed, ucontrol->value.integer.value[0],
+ dbri->mm.data[elem & 3]);
+
+ if (changed) {
+ /* First mute outputs, and wait 1/8000 sec (125 us)
+ * to make sure this takes. This avoids clicking noises.
+ */
+ spin_lock_irqsave(&dbri->lock, flags);
+
+ cs4215_setdata(dbri, 1);
+ udelay(125);
+ cs4215_setdata(dbri, 0);
+
+ spin_unlock_irqrestore(&dbri->lock, flags);
+ }
+ return changed;
+}
+
+/* Entries 0-3 map to the 4 data timeslots, entries 4-7 map to the 4 control
+ timeslots. Shift is the bit offset in the timeslot, mask defines the
+ number of bits. invert is a boolean for use with attenuation.
+ */
+#define CS4215_SINGLE(xname, entry, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_cs4215_info_single, \
+ .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \
+ .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) },
+
+static snd_kcontrol_new_t dbri_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Playback Volume",
+ .info = snd_cs4215_info_volume,
+ .get = snd_cs4215_get_volume,
+ .put = snd_cs4215_put_volume,
+ .private_value = DBRI_PLAY,
+ },
+ CS4215_SINGLE("Headphone switch", 0, 7, 1, 0)
+ CS4215_SINGLE("Line out switch", 0, 6, 1, 0)
+ CS4215_SINGLE("Speaker switch", 1, 6, 1, 0)
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Volume",
+ .info = snd_cs4215_info_volume,
+ .get = snd_cs4215_get_volume,
+ .put = snd_cs4215_put_volume,
+ .private_value = DBRI_REC,
+ },
+ /* FIXME: mic/line switch */
+ CS4215_SINGLE("Line in switch", 2, 4, 1, 0)
+ CS4215_SINGLE("High Pass Filter switch", 5, 7, 1, 0)
+ CS4215_SINGLE("Monitor Volume", 3, 4, 0xf, 1)
+ CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
+};
+
+#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(snd_kcontrol_new_t))
+
+static int __init snd_dbri_mixer(snd_dbri_t * dbri)
+{
+ snd_card_t *card;
+ int idx, err;
+
+ snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL);
+
+ card = dbri->card;
+ strcpy(card->mixername, card->shortname);
+
+ for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) {
+ if ((err = snd_ctl_add(card,
+ snd_ctl_new1(&dbri_controls[idx],
+ dbri))) < 0)
+ return err;
+ }
+
+ for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) {
+ dbri->stream_info[idx].left_gain = 0;
+ dbri->stream_info[idx].right_gain = 0;
+ dbri->stream_info[idx].balance = DBRI_MID_BALANCE;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ /proc interface
+****************************************************************************/
+static void dbri_regs_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer)
+{
+ snd_dbri_t *dbri = entry->private_data;
+
+ snd_iprintf(buffer, "REG0: 0x%x\n", sbus_readl(dbri->regs + REG0));
+ snd_iprintf(buffer, "REG2: 0x%x\n", sbus_readl(dbri->regs + REG2));
+ snd_iprintf(buffer, "REG8: 0x%x\n", sbus_readl(dbri->regs + REG8));
+ snd_iprintf(buffer, "REG9: 0x%x\n", sbus_readl(dbri->regs + REG9));
+}
+
+#ifdef DBRI_DEBUG
+static void dbri_debug_read(snd_info_entry_t * entry,
+ snd_info_buffer_t * buffer)
+{
+ snd_dbri_t *dbri = entry->private_data;
+ int pipe;
+ snd_iprintf(buffer, "debug=%d\n", dbri_debug);
+
+ snd_iprintf(buffer, "CHI pipe in=%d, out=%d\n",
+ dbri->chi_in_pipe, dbri->chi_out_pipe);
+ for (pipe = 0; pipe < 32; pipe++) {
+ if (pipe_active(dbri, pipe)) {
+ struct dbri_pipe *pptr = &dbri->pipes[pipe];
+ snd_iprintf(buffer,
+ "Pipe %d: %s SDP=0x%x desc=%d, "
+ "len=%d @ %d prev: %d next %d\n",
+ pipe,
+ (pptr->direction ==
+ PIPEinput ? "input" : "output"), pptr->sdp,
+ pptr->desc, pptr->length, pptr->cycle,
+ pptr->prevpipe, pptr->nextpipe);
+ }
+ }
+}
+
+static void dbri_debug_write(snd_info_entry_t * entry,
+ snd_info_buffer_t * buffer)
+{
+ char line[80];
+ int i;
+
+ if (snd_info_get_line(buffer, line, 80) == 0) {
+ sscanf(line, "%d\n", &i);
+ dbri_debug = i & 0x3f;
+ }
+}
+#endif
+
+void snd_dbri_proc(snd_dbri_t * dbri)
+{
+ snd_info_entry_t *entry;
+ int err;
+
+ err = snd_card_proc_new(dbri->card, "regs", &entry);
+ snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read);
+
+#ifdef DBRI_DEBUG
+ err = snd_card_proc_new(dbri->card, "debug", &entry);
+ snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read);
+ entry->mode = S_IFREG | S_IRUGO | S_IWUSR; /* Writable for root */
+ entry->c.text.write_size = 256;
+ entry->c.text.write = dbri_debug_write;
+#endif
+}
+
+/*
+****************************************************************************
+**************************** Initialization ********************************
+****************************************************************************
+*/
+static void snd_dbri_free(snd_dbri_t * dbri);
+
+static int __init snd_dbri_create(snd_card_t * card,
+ struct sbus_dev *sdev,
+ struct linux_prom_irqs *irq, int dev)
+{
+ snd_dbri_t *dbri = card->private_data;
+ int err;
+
+ spin_lock_init(&dbri->lock);
+ dbri->card = card;
+ dbri->sdev = sdev;
+ dbri->irq = irq->pri;
+ dbri->dbri_version = sdev->prom_name[9];
+
+ dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
+ &dbri->dma_dvma);
+ memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
+
+ dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
+ dbri->dma, dbri->dma_dvma);
+
+ /* Map the registers into memory. */
+ dbri->regs_size = sdev->reg_addrs[0].reg_size;
+ dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
+ dbri->regs_size, "DBRI Registers");
+ if (!dbri->regs) {
+ printk(KERN_ERR "DBRI: could not allocate registers\n");
+ sbus_free_consistent(sdev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
+ return -EIO;
+ }
+
+ err = request_irq(dbri->irq, snd_dbri_interrupt, SA_SHIRQ,
+ "DBRI audio", dbri);
+ if (err) {
+ printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
+ sbus_iounmap(dbri->regs, dbri->regs_size);
+ sbus_free_consistent(sdev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
+ return err;
+ }
+
+ /* Do low level initialization of the DBRI and CS4215 chips */
+ dbri_initialize(dbri);
+ err = cs4215_init(dbri);
+ if (err) {
+ snd_dbri_free(dbri);
+ return err;
+ }
+
+ dbri->next = dbri_list;
+ dbri_list = dbri;
+
+ return 0;
+}
+
+static void snd_dbri_free(snd_dbri_t * dbri)
+{
+ dprintk(D_GEN, "snd_dbri_free\n");
+ dbri_reset(dbri);
+
+ if (dbri->irq)
+ free_irq(dbri->irq, dbri);
+
+ if (dbri->regs)
+ sbus_iounmap(dbri->regs, dbri->regs_size);
+
+ if (dbri->dma)
+ sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
+ (void *)dbri->dma, dbri->dma_dvma);
+}
+
+static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
+{
+ snd_dbri_t *dbri;
+ struct linux_prom_irqs irq;
+ struct resource *rp;
+ snd_card_t *card;
+ static int dev = 0;
+ int err;
+
+ if (sdev->prom_name[9] < 'e') {
+ printk(KERN_ERR "DBRI: unsupported chip version %c found.\n",
+ sdev->prom_name[9]);
+ return -EIO;
+ }
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq));
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+ sizeof(snd_dbri_t));
+ if (card == NULL)
+ return -ENOMEM;
+
+ strcpy(card->driver, "DBRI");
+ strcpy(card->shortname, "Sun DBRI");
+ rp = &sdev->resource[0];
+ sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
+ card->shortname,
+ rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri));
+
+ if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ dbri = (snd_dbri_t *) card->private_data;
+ if ((err = snd_dbri_pcm(dbri)) < 0) {
+ snd_dbri_free(dbri);
+ snd_card_free(card);
+ return err;
+ }
+
+ if ((err = snd_dbri_mixer(dbri)) < 0) {
+ snd_dbri_free(dbri);
+ snd_card_free(card);
+ return err;
+ }
+
+ /* /proc file handling */
+ snd_dbri_proc(dbri);
+
+ if ((err = snd_card_register(card)) < 0) {
+ snd_dbri_free(dbri);
+ snd_card_free(card);
+ return err;
+ }
+
+ printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
+ dev, dbri->regs,
+ dbri->irq, dbri->dbri_version, dbri->mm.version);
+ dev++;
+
+ return 0;
+}
+
+/* Probe for the dbri chip and then attach the driver. */
+static int __init dbri_init(void)
+{
+ struct sbus_bus *sbus;
+ struct sbus_dev *sdev;
+ int found = 0;
+
+ /* Probe each SBUS for the DBRI chip(s). */
+ for_all_sbusdev(sdev, sbus) {
+ /*
+ * The version is coded in the last character
+ */
+ if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) {
+ dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
+ sdev->prom_name, sdev->slot);
+
+ if (dbri_attach(sdev->prom_node, sdev) == 0)
+ found++;
+ }
+ }
+
+ return (found > 0) ? 0 : -EIO;
+}
+
+static void __exit dbri_exit(void)
+{
+ snd_dbri_t *this = dbri_list;
+
+ while (this != NULL) {
+ snd_dbri_t *next = this->next;
+ snd_card_t *card = this->card;
+
+ snd_dbri_free(this);
+ snd_card_free(card);
+ this = next;
+ }
+ dbri_list = NULL;
+}
+
+module_init(dbri_init);
+module_exit(dbri_exit);
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c
index f13b038329eb..751bf1272af3 100644
--- a/sound/synth/emux/emux_synth.c
+++ b/sound/synth/emux/emux_synth.c
@@ -98,7 +98,6 @@ snd_emux_note_on(void *p, int note, int vel, snd_midi_channel_t *chan)
vp = emu->ops.get_voice(emu, port);
if (vp == NULL || vp->ch < 0)
continue;
- snd_assert(vp->emu != NULL && vp->hw != NULL, return);
if (STATE_IS_PLAYING(vp->state))
emu->ops.terminate(vp);
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index a75695045f29..5aa5fe651a8a 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -41,10 +41,12 @@
#include <sound/driver.h>
#include <linux/bitops.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
+#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/info.h>
@@ -79,7 +81,7 @@ module_param_array(vid, int, NULL, 0444);
MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
module_param_array(pid, int, NULL, 0444);
MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-module_param(nrpacks, int, 0444);
+module_param(nrpacks, int, 0644);
MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
module_param(async_unlink, bool, 0444);
MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
@@ -97,7 +99,7 @@ MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
#define MAX_PACKS 10
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS 5 /* max. 20ms long packets */
+#define MAX_URBS 8
#define SYNC_URBS 4 /* always four urbs for sync */
#define MIN_PACKS_URB 1 /* minimum 1 packet per urb */
@@ -126,11 +128,10 @@ struct audioformat {
struct snd_urb_ctx {
struct urb *urb;
+ unsigned int buffer_size; /* size of data buffer, if data URB */
snd_usb_substream_t *subs;
int index; /* index for urb array */
int packets; /* number of packets per urb */
- int transfer; /* transferred size */
- char *buf; /* buffer for capture */
};
struct snd_urb_ops {
@@ -153,6 +154,7 @@ struct snd_usb_substream {
unsigned int format; /* USB data format */
unsigned int datapipe; /* the data i/o pipe */
unsigned int syncpipe; /* 1 - async out or adaptive in */
+ unsigned int datainterval; /* log_2 of data packet interval */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
@@ -164,12 +166,11 @@ struct snd_usb_substream {
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int fill_max: 1; /* fill max packet size always */
unsigned int fmt_type; /* USB audio format type (1-3) */
+ unsigned int packs_per_ms; /* packets per millisecond (for playback) */
unsigned int running: 1; /* running status */
- unsigned int hwptr; /* free frame position in the buffer (only for playback) */
unsigned int hwptr_done; /* processed frame position in the buffer */
- unsigned int transfer_sched; /* scheduled frames since last period (for playback) */
unsigned int transfer_done; /* processed frames since last period update */
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
@@ -177,13 +178,14 @@ struct snd_usb_substream {
unsigned int nurbs; /* # urbs */
snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */
snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */
- char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */
- char *tmpbuf; /* temporary buffer for playback */
+ char *syncbuf; /* sync buffer for all sync URBs */
+ dma_addr_t sync_dma; /* DMA address of syncbuf */
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
struct list_head fmt_list; /* format list */
spinlock_t lock;
+ struct tasklet_struct start_period_elapsed; /* for start trigger */
struct snd_urb_ops ops; /* callbacks (must be filled at init) */
};
@@ -212,7 +214,7 @@ static snd_usb_audio_t *usb_chip[SNDRV_CARDS];
* convert a sampling rate into our full speed format (fs/1000 in Q16.16)
* this will overflow at approx 524 kHz
*/
-inline static unsigned get_usb_full_speed_rate(unsigned int rate)
+static inline unsigned get_usb_full_speed_rate(unsigned int rate)
{
return ((rate << 13) + 62) / 125;
}
@@ -221,19 +223,19 @@ inline static unsigned get_usb_full_speed_rate(unsigned int rate)
* convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
* this will overflow at approx 4 MHz
*/
-inline static unsigned get_usb_high_speed_rate(unsigned int rate)
+static inline unsigned get_usb_high_speed_rate(unsigned int rate)
{
return ((rate << 10) + 62) / 125;
}
/* convert our full speed USB rate into sampling rate in Hz */
-inline static unsigned get_full_speed_hz(unsigned int usb_rate)
+static inline unsigned get_full_speed_hz(unsigned int usb_rate)
{
return (usb_rate * 125 + (1 << 12)) >> 13;
}
/* convert our high speed USB rate into sampling rate in Hz */
-inline static unsigned get_high_speed_hz(unsigned int usb_rate)
+static inline unsigned get_high_speed_hz(unsigned int usb_rate)
{
return (usb_rate * 125 + (1 << 9)) >> 10;
}
@@ -310,27 +312,17 @@ static int prepare_capture_urb(snd_usb_substream_t *subs,
struct urb *urb)
{
int i, offs;
- unsigned long flags;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
offs = 0;
urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->number_of_packets = 0;
- spin_lock_irqsave(&subs->lock, flags);
for (i = 0; i < ctx->packets; i++) {
urb->iso_frame_desc[i].offset = offs;
urb->iso_frame_desc[i].length = subs->curpacksize;
offs += subs->curpacksize;
- urb->number_of_packets++;
- subs->transfer_sched += subs->curframesize;
- if (subs->transfer_sched >= runtime->period_size) {
- subs->transfer_sched -= runtime->period_size;
- break;
- }
}
- spin_unlock_irqrestore(&subs->lock, flags);
- urb->transfer_buffer = ctx->buf;
urb->transfer_buffer_length = offs;
+ urb->number_of_packets = ctx->packets;
#if 0 // for check
if (! urb->bandwidth) {
int bustime;
@@ -358,6 +350,7 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
unsigned char *cp;
int i;
unsigned int stride, len, oldptr;
+ int period_elapsed = 0;
stride = runtime->frame_bits >> 3;
@@ -377,6 +370,10 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
if (subs->hwptr_done >= runtime->buffer_size)
subs->hwptr_done -= runtime->buffer_size;
subs->transfer_done += len;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
+ }
spin_unlock_irqrestore(&subs->lock, flags);
/* copy a data chunk */
if (oldptr + len > runtime->buffer_size) {
@@ -387,15 +384,9 @@ static int retire_capture_urb(snd_usb_substream_t *subs,
} else {
memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
}
- /* update the pointer, call callback if necessary */
- spin_lock_irqsave(&subs->lock, flags);
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- spin_unlock_irqrestore(&subs->lock, flags);
- snd_pcm_period_elapsed(subs->pcm_substream);
- } else
- spin_unlock_irqrestore(&subs->lock, flags);
}
+ if (period_elapsed)
+ snd_pcm_period_elapsed(subs->pcm_substream);
return 0;
}
@@ -491,12 +482,10 @@ static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
/*
* prepare urb for playback data pipe
*
- * we copy the data directly from the pcm buffer.
- * the current position to be copied is held in hwptr field.
- * since a urb can handle only a single linear buffer, if the total
- * transferred area overflows the buffer boundary, we cannot send
- * it directly from the buffer. thus the data is once copied to
- * a temporary buffer and urb points to that.
+ * Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
*/
static int prepare_playback_urb(snd_usb_substream_t *subs,
snd_pcm_runtime_t *runtime,
@@ -505,6 +494,7 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
int i, stride, offs;
unsigned int counts;
unsigned long flags;
+ int period_elapsed = 0;
snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
stride = runtime->frame_bits >> 3;
@@ -518,7 +508,8 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
if (subs->fill_max)
counts = subs->maxframesize; /* fixed */
else {
- subs->phase = (subs->phase & 0xffff) + subs->freqm;
+ subs->phase = (subs->phase & 0xffff)
+ + (subs->freqm << subs->datainterval);
counts = subs->phase >> 16;
if (counts > subs->maxframesize)
counts = subs->maxframesize;
@@ -528,80 +519,85 @@ static int prepare_playback_urb(snd_usb_substream_t *subs,
urb->iso_frame_desc[i].length = counts * stride;
offs += counts;
urb->number_of_packets++;
- subs->transfer_sched += counts;
- if (subs->transfer_sched >= runtime->period_size) {
- subs->transfer_sched -= runtime->period_size;
+ subs->transfer_done += counts;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
if (subs->fmt_type == USB_FORMAT_TYPE_II) {
- if (subs->transfer_sched > 0) {
- /* FIXME: fill-max mode is not supported yet */
- offs -= subs->transfer_sched;
- counts -= subs->transfer_sched;
- urb->iso_frame_desc[i].length = counts * stride;
- subs->transfer_sched = 0;
+ if (subs->transfer_done > 0) {
+ /* FIXME: fill-max mode is not
+ * supported yet */
+ offs -= subs->transfer_done;
+ counts -= subs->transfer_done;
+ urb->iso_frame_desc[i].length =
+ counts * stride;
+ subs->transfer_done = 0;
}
i++;
if (i < ctx->packets) {
/* add a transfer delimiter */
- urb->iso_frame_desc[i].offset = offs * stride;
+ urb->iso_frame_desc[i].offset =
+ offs * stride;
urb->iso_frame_desc[i].length = 0;
urb->number_of_packets++;
}
+ break;
}
- break;
}
+ /* finish at the frame boundary at/after the period boundary */
+ if (period_elapsed &&
+ (i & (subs->packs_per_ms - 1)) == subs->packs_per_ms - 1)
+ break;
}
- if (subs->hwptr + offs > runtime->buffer_size) {
- /* err, the transferred area goes over buffer boundary.
- * copy the data to the temp buffer.
- */
- int len;
- len = runtime->buffer_size - subs->hwptr;
- urb->transfer_buffer = subs->tmpbuf;
- memcpy(subs->tmpbuf, runtime->dma_area + subs->hwptr * stride, len * stride);
- memcpy(subs->tmpbuf + len * stride, runtime->dma_area, (offs - len) * stride);
- subs->hwptr += offs;
- subs->hwptr -= runtime->buffer_size;
+ if (subs->hwptr_done + offs > runtime->buffer_size) {
+ /* err, the transferred area goes over buffer boundary. */
+ unsigned int len = runtime->buffer_size - subs->hwptr_done;
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done * stride,
+ len * stride);
+ memcpy(urb->transfer_buffer + len * stride,
+ runtime->dma_area,
+ (offs - len) * stride);
} else {
- /* set the buffer pointer */
- urb->transfer_buffer = runtime->dma_area + subs->hwptr * stride;
- subs->hwptr += offs;
- if (subs->hwptr == runtime->buffer_size)
- subs->hwptr = 0;
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done * stride,
+ offs * stride);
}
+ subs->hwptr_done += offs;
+ if (subs->hwptr_done >= runtime->buffer_size)
+ subs->hwptr_done -= runtime->buffer_size;
spin_unlock_irqrestore(&subs->lock, flags);
urb->transfer_buffer_length = offs * stride;
- ctx->transfer = offs;
-
+ if (period_elapsed) {
+ if (likely(subs->running))
+ snd_pcm_period_elapsed(subs->pcm_substream);
+ else
+ tasklet_hi_schedule(&subs->start_period_elapsed);
+ }
return 0;
}
/*
* process after playback data complete
- *
- * update the current position and call callback if a period is processed.
+ * - nothing to do
*/
static int retire_playback_urb(snd_usb_substream_t *subs,
snd_pcm_runtime_t *runtime,
struct urb *urb)
{
- unsigned long flags;
- snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
-
- spin_lock_irqsave(&subs->lock, flags);
- subs->transfer_done += ctx->transfer;
- subs->hwptr_done += ctx->transfer;
- ctx->transfer = 0;
- if (subs->hwptr_done >= runtime->buffer_size)
- subs->hwptr_done -= runtime->buffer_size;
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- spin_unlock_irqrestore(&subs->lock, flags);
- snd_pcm_period_elapsed(subs->pcm_substream);
- } else
- spin_unlock_irqrestore(&subs->lock, flags);
return 0;
}
+/*
+ * Delay the snd_pcm_period_elapsed() call until after the start trigger
+ * callback so that we're not longer in the substream's lock.
+ */
+static void start_period_elapsed(unsigned long data)
+{
+ snd_usb_substream_t *subs = (snd_usb_substream_t *)data;
+ snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
/*
*/
@@ -681,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
}
+/* get the physical page pointer at the given offset */
+static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
+ unsigned long offset)
+{
+ void *pageptr = subs->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+/* allocate virtual buffer; may be called more than once */
+static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
+{
+ snd_pcm_runtime_t *runtime = subs->runtime;
+ if (runtime->dma_area) {
+ if (runtime->dma_bytes >= size)
+ return 0; /* already large enough */
+ vfree_nocheck(runtime->dma_area);
+ }
+ runtime->dma_area = vmalloc_nocheck(size);
+ if (! runtime->dma_area)
+ return -ENOMEM;
+ runtime->dma_bytes = size;
+ return 0;
+}
+
+/* free virtual buffer; may be called more than once */
+static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
+{
+ snd_pcm_runtime_t *runtime = subs->runtime;
+ if (runtime->dma_area) {
+ vfree_nocheck(runtime->dma_area);
+ runtime->dma_area = NULL;
+ }
+ return 0;
+}
+
+
/*
* unlink active urbs.
*/
@@ -790,7 +822,7 @@ static int start_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime)
*/
static int wait_clear_urbs(snd_usb_substream_t *subs)
{
- int timeout = HZ;
+ unsigned long end_time = jiffies + msecs_to_jiffies(1000);
unsigned int i;
int alive;
@@ -810,7 +842,7 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
- } while (--timeout > 0);
+ } while (time_before(jiffies, end_time));
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
return 0;
@@ -822,8 +854,14 @@ static int wait_clear_urbs(snd_usb_substream_t *subs)
*/
static snd_pcm_uframes_t snd_usb_pcm_pointer(snd_pcm_substream_t *substream)
{
- snd_usb_substream_t *subs = (snd_usb_substream_t *)substream->runtime->private_data;
- return subs->hwptr_done;
+ snd_usb_substream_t *subs;
+ snd_pcm_uframes_t hwptr_done;
+
+ subs = (snd_usb_substream_t *)substream->runtime->private_data;
+ spin_lock(&subs->lock);
+ hwptr_done = subs->hwptr_done;
+ spin_unlock(&subs->lock);
+ return hwptr_done;
}
@@ -856,11 +894,13 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
static void release_urb_ctx(snd_urb_ctx_t *u)
{
if (u->urb) {
+ if (u->buffer_size)
+ usb_buffer_free(u->subs->dev, u->buffer_size,
+ u->urb->transfer_buffer,
+ u->urb->transfer_dma);
usb_free_urb(u->urb);
u->urb = NULL;
}
- kfree(u->buf);
- u->buf = NULL;
}
/*
@@ -878,8 +918,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
release_urb_ctx(&subs->dataurb[i]);
for (i = 0; i < SYNC_URBS; i++)
release_urb_ctx(&subs->syncurb[i]);
- kfree(subs->tmpbuf);
- subs->tmpbuf = NULL;
+ usb_buffer_free(subs->dev, SYNC_URBS * 4,
+ subs->syncbuf, subs->sync_dma);
+ subs->syncbuf = NULL;
subs->nurbs = 0;
}
@@ -891,7 +932,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
{
unsigned int maxsize, n, i;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned int npacks[MAX_URBS], urb_packs, total_packs;
+ unsigned int npacks[MAX_URBS], urb_packs, total_packs, packs_per_ms;
/* calculate the frequency in 16.16 format */
if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
@@ -899,40 +940,59 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
else
subs->freqn = get_usb_high_speed_rate(rate);
subs->freqm = subs->freqn;
- subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
- subs->phase = 0;
-
- /* calculate the max. size of packet */
- maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16;
- if (subs->maxpacksize && maxsize > subs->maxpacksize) {
- //snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
- // maxsize, subs->maxpacksize);
+ /* calculate max. frequency */
+ if (subs->maxpacksize) {
+ /* whatever fits into a max. size packet */
maxsize = subs->maxpacksize;
+ subs->freqmax = (maxsize / (frame_bits >> 3))
+ << (16 - subs->datainterval);
+ } else {
+ /* no max. packet size: just take 25% higher than nominal */
+ subs->freqmax = subs->freqn + (subs->freqn >> 2);
+ maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
+ >> (16 - subs->datainterval);
}
+ subs->phase = 0;
if (subs->fill_max)
subs->curpacksize = subs->maxpacksize;
else
subs->curpacksize = maxsize;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
- urb_packs = nrpacks;
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+ packs_per_ms = 8 >> subs->datainterval;
else
- urb_packs = nrpacks * 8;
+ packs_per_ms = 1;
+ subs->packs_per_ms = packs_per_ms;
- /* allocate a temporary buffer for playback */
if (is_playback) {
- subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
- if (! subs->tmpbuf) {
- snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
- return -ENOMEM;
- }
- }
+ urb_packs = nrpacks;
+ urb_packs = max(urb_packs, (unsigned int)MIN_PACKS_URB);
+ urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
+ } else
+ urb_packs = 1;
+ urb_packs *= packs_per_ms;
/* decide how many packets to be used */
- total_packs = (period_bytes + maxsize - 1) / maxsize;
- if (total_packs < 2 * MIN_PACKS_URB)
- total_packs = 2 * MIN_PACKS_URB;
+ if (is_playback) {
+ unsigned int minsize;
+ /* determine how small a packet can be */
+ minsize = (subs->freqn >> (16 - subs->datainterval))
+ * (frame_bits >> 3);
+ /* with sync from device, assume it can be 12% lower */
+ if (subs->syncpipe)
+ minsize -= minsize >> 3;
+ minsize = max(minsize, 1u);
+ total_packs = (period_bytes + minsize - 1) / minsize;
+ /* round up to multiple of packs_per_ms */
+ total_packs = (total_packs + packs_per_ms - 1)
+ & ~(packs_per_ms - 1);
+ /* we need at least two URBs for queueing */
+ if (total_packs < 2 * MIN_PACKS_URB * packs_per_ms)
+ total_packs = 2 * MIN_PACKS_URB * packs_per_ms;
+ } else {
+ total_packs = MAX_URBS * urb_packs;
+ }
subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
if (subs->nurbs > MAX_URBS) {
/* too much... */
@@ -951,7 +1011,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
subs->nurbs = 2;
npacks[0] = (total_packs + 1) / 2;
npacks[1] = total_packs - npacks[0];
- } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB) {
+ } else if (npacks[subs->nurbs-1] < MIN_PACKS_URB * packs_per_ms) {
/* the last packet is too small.. */
if (subs->nurbs > 2) {
/* merge to the first one */
@@ -970,49 +1030,45 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
snd_urb_ctx_t *u = &subs->dataurb[i];
u->index = i;
u->subs = subs;
- u->transfer = 0;
u->packets = npacks[i];
+ u->buffer_size = maxsize * u->packets;
if (subs->fmt_type == USB_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */
- if (! is_playback) {
- /* allocate a capture buffer per urb */
- u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL);
- if (! u->buf) {
- release_substream_urbs(subs, 0);
- return -ENOMEM;
- }
- }
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
- if (! u->urb) {
- release_substream_urbs(subs, 0);
- return -ENOMEM;
- }
- u->urb->dev = subs->dev;
+ if (! u->urb)
+ goto out_of_memory;
+ u->urb->transfer_buffer =
+ usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
+ &u->urb->transfer_dma);
+ if (! u->urb->transfer_buffer)
+ goto out_of_memory;
u->urb->pipe = subs->datapipe;
- u->urb->transfer_flags = URB_ISO_ASAP;
- u->urb->number_of_packets = u->packets;
- u->urb->interval = 1;
+ u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ u->urb->interval = 1 << subs->datainterval;
u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
}
if (subs->syncpipe) {
/* allocate and initialize sync urbs */
+ subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
+ GFP_KERNEL, &subs->sync_dma);
+ if (! subs->syncbuf)
+ goto out_of_memory;
for (i = 0; i < SYNC_URBS; i++) {
snd_urb_ctx_t *u = &subs->syncurb[i];
u->index = i;
u->subs = subs;
u->packets = 1;
u->urb = usb_alloc_urb(1, GFP_KERNEL);
- if (! u->urb) {
- release_substream_urbs(subs, 0);
- return -ENOMEM;
- }
+ if (! u->urb)
+ goto out_of_memory;
u->urb->transfer_buffer = subs->syncbuf + i * 4;
+ u->urb->transfer_dma = subs->sync_dma + i * 4;
u->urb->transfer_buffer_length = 4;
- u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
- u->urb->transfer_flags = URB_ISO_ASAP;
+ u->urb->transfer_flags = URB_ISO_ASAP |
+ URB_NO_TRANSFER_DMA_MAP;
u->urb->number_of_packets = 1;
u->urb->interval = 1 << subs->syncinterval;
u->urb->context = u;
@@ -1020,6 +1076,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
}
}
return 0;
+
+out_of_memory:
+ release_substream_urbs(subs, 0);
+ return -ENOMEM;
}
@@ -1195,6 +1255,12 @@ static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
subs->datapipe = usb_sndisocpipe(dev, ep);
else
subs->datapipe = usb_rcvisocpipe(dev, ep);
+ if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH &&
+ get_endpoint(alts, 0)->bInterval >= 1 &&
+ get_endpoint(alts, 0)->bInterval <= 4)
+ subs->datainterval = get_endpoint(alts, 0)->bInterval - 1;
+ else
+ subs->datainterval = 0;
subs->syncpipe = subs->syncinterval = 0;
subs->maxpacksize = fmt->maxpacksize;
subs->fill_max = 0;
@@ -1282,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
unsigned int channels, rate, format;
int ret, changed;
- ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+ ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
@@ -1338,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
subs->cur_rate = 0;
subs->period_bytes = 0;
release_substream_urbs(subs, 0);
- return snd_pcm_lib_free_pages(substream);
+ return snd_pcm_free_vmalloc_buffer(substream);
}
/*
@@ -1361,9 +1428,7 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream)
subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
/* reset the pointer */
- subs->hwptr = 0;
subs->hwptr_done = 0;
- subs->transfer_sched = 0;
subs->transfer_done = 0;
subs->phase = 0;
@@ -1379,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
- .buffer_bytes_max = (128*1024),
+ .buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
@@ -1391,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
- .buffer_bytes_max = (128*1024),
+ .buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
@@ -1783,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
static snd_pcm_ops_t snd_usb_capture_ops = {
@@ -1794,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
+ .page = snd_pcm_get_vmalloc_page,
};
@@ -2010,6 +2077,9 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
INIT_LIST_HEAD(&subs->fmt_list);
spin_lock_init(&subs->lock);
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tasklet_init(&subs->start_period_elapsed, start_period_elapsed,
+ (unsigned long)subs);
subs->stream = as;
subs->direction = stream;
@@ -2018,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->ops = audio_urb_ops[stream];
else
subs->ops = audio_urb_ops_high_speed[stream];
- snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
- SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data(GFP_KERNEL),
- 64 * 1024, 128 * 1024);
snd_pcm_set_ops(as->pcm, stream,
stream == SNDRV_PCM_STREAM_PLAYBACK ?
&snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -2067,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
snd_usb_stream_t *stream = pcm->private_data;
if (stream) {
stream->pcm = NULL;
- snd_pcm_lib_preallocate_free_for_all(pcm);
snd_usb_audio_stream_free(stream);
}
}
@@ -2397,10 +2462,9 @@ static int parse_audio_format(snd_usb_audio_t *chip, struct audioformat *fp,
if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
chip->usb_id == USB_ID(0x041e, 0x3020)) {
if (fmt[3] == USB_FORMAT_TYPE_I &&
- stream == SNDRV_PCM_STREAM_PLAYBACK &&
fp->rates != SNDRV_PCM_RATE_48000 &&
fp->rates != SNDRV_PCM_RATE_96000)
- return -1; /* use 48k only */
+ return -1;
}
#endif
return 0;
@@ -2492,8 +2556,10 @@ static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
fp->altset_idx = i;
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
- /* FIXME: decode wMaxPacketSize of high bandwith endpoints */
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+ if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
+ fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
+ * (fp->maxpacksize & 0x7ff);
fp->attributes = csep[3];
/* some quirks for attributes here */
@@ -2723,7 +2789,8 @@ static int create_standard_interface_quirk(snd_usb_audio_t *chip,
* to detect the sample rate is by looking at wMaxPacketSize.
*/
static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
- struct usb_interface *iface)
+ struct usb_interface *iface,
+ const snd_usb_audio_quirk_t *quirk)
{
static const struct audioformat ua_format = {
.format = SNDRV_PCM_FORMAT_S24_3LE,
@@ -2814,7 +2881,9 @@ static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
/*
* Create a stream for an Edirol UA-1000 interface.
*/
-static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface)
+static int create_ua1000_quirk(snd_usb_audio_t *chip,
+ struct usb_interface *iface,
+ const snd_usb_audio_quirk_t *quirk)
{
static const struct audioformat ua1000_format = {
.format = SNDRV_PCM_FORMAT_S32_LE,
@@ -2891,6 +2960,13 @@ static int create_composite_quirk(snd_usb_audio_t *chip,
return 0;
}
+static int ignore_interface_quirk(snd_usb_audio_t *chip,
+ struct usb_interface *iface,
+ const snd_usb_audio_quirk_t *quirk)
+{
+ return 0;
+}
+
/*
* boot quirks
@@ -2926,8 +3002,6 @@ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interfac
static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
{
-#if 0
- /* TODO: enable this when high speed synchronization actually works */
u8 buf = 1;
snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
@@ -2939,7 +3013,6 @@ static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
1, 2000, NULL, 0, 1000);
return -ENODEV;
}
-#endif
return 0;
}
@@ -2956,28 +3029,28 @@ static int snd_usb_create_quirk(snd_usb_audio_t *chip,
struct usb_interface *iface,
const snd_usb_audio_quirk_t *quirk)
{
- switch (quirk->type) {
- case QUIRK_MIDI_FIXED_ENDPOINT:
- case QUIRK_MIDI_YAMAHA:
- case QUIRK_MIDI_MIDIMAN:
- case QUIRK_MIDI_NOVATION:
- case QUIRK_MIDI_MOTU:
- case QUIRK_MIDI_EMAGIC:
- return snd_usb_create_midi_interface(chip, iface, quirk);
- case QUIRK_COMPOSITE:
- return create_composite_quirk(chip, iface, quirk);
- case QUIRK_AUDIO_FIXED_ENDPOINT:
- return create_fixed_stream_quirk(chip, iface, quirk);
- case QUIRK_AUDIO_STANDARD_INTERFACE:
- case QUIRK_MIDI_STANDARD_INTERFACE:
- return create_standard_interface_quirk(chip, iface, quirk);
- case QUIRK_AUDIO_EDIROL_UA700_UA25:
- return create_ua700_ua25_quirk(chip, iface);
- case QUIRK_AUDIO_EDIROL_UA1000:
- return create_ua1000_quirk(chip, iface);
- case QUIRK_IGNORE_INTERFACE:
- return 0;
- default:
+ typedef int (*quirk_func_t)(snd_usb_audio_t *, struct usb_interface *,
+ const snd_usb_audio_quirk_t *);
+ static const quirk_func_t quirk_funcs[] = {
+ [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
+ [QUIRK_COMPOSITE] = create_composite_quirk,
+ [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_RAW] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
+ [QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface,
+ [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_interface_quirk,
+ [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
+ [QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
+ [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
+ };
+
+ if (quirk->type < QUIRK_TYPE_COUNT) {
+ return quirk_funcs[quirk->type](chip, iface, quirk);
+ } else {
snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
return -ENXIO;
}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index aedb42aaa749..ad9eab211d8f 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -153,20 +153,24 @@ struct snd_usb_audio {
#define QUIRK_NO_INTERFACE -2
#define QUIRK_ANY_INTERFACE -1
-/* quirk type */
-#define QUIRK_MIDI_FIXED_ENDPOINT 0
-#define QUIRK_MIDI_YAMAHA 1
-#define QUIRK_MIDI_MIDIMAN 2
-#define QUIRK_COMPOSITE 3
-#define QUIRK_AUDIO_FIXED_ENDPOINT 4
-#define QUIRK_AUDIO_STANDARD_INTERFACE 5
-#define QUIRK_MIDI_STANDARD_INTERFACE 6
-#define QUIRK_AUDIO_EDIROL_UA700_UA25 7
-#define QUIRK_AUDIO_EDIROL_UA1000 8
-#define QUIRK_IGNORE_INTERFACE 9
-#define QUIRK_MIDI_NOVATION 10
-#define QUIRK_MIDI_MOTU 11
-#define QUIRK_MIDI_EMAGIC 12
+enum quirk_type {
+ QUIRK_IGNORE_INTERFACE,
+ QUIRK_COMPOSITE,
+ QUIRK_MIDI_STANDARD_INTERFACE,
+ QUIRK_MIDI_FIXED_ENDPOINT,
+ QUIRK_MIDI_YAMAHA,
+ QUIRK_MIDI_MIDIMAN,
+ QUIRK_MIDI_NOVATION,
+ QUIRK_MIDI_RAW,
+ QUIRK_MIDI_EMAGIC,
+ QUIRK_MIDI_MIDITECH,
+ QUIRK_AUDIO_STANDARD_INTERFACE,
+ QUIRK_AUDIO_FIXED_ENDPOINT,
+ QUIRK_AUDIO_EDIROL_UA700_UA25,
+ QUIRK_AUDIO_EDIROL_UA1000,
+
+ QUIRK_TYPE_COUNT
+};
typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -175,7 +179,7 @@ struct snd_usb_audio_quirk {
const char *vendor_name;
const char *product_name;
int16_t ifnum;
- int16_t type;
+ uint16_t type;
const void *data;
};
@@ -205,11 +209,13 @@ struct snd_usb_midi_endpoint_info {
/* for QUIRK_IGNORE_INTERFACE, data is NULL */
-/* for QUIRK_MIDI_NOVATION and _MOTU, data is NULL */
+/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */
/* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info
* structure (out_cables and in_cables only) */
+/* for QUIRK_MIDI_MIDITECH, data is NULL */
+
/*
*/
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index bee70068dce0..93dedde3c428 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/timer.h>
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/minors.h>
@@ -56,6 +57,12 @@
*/
/* #define DUMP_PACKETS */
+/*
+ * how long to wait after some USB errors, so that khubd can disconnect() us
+ * without too many spurious errors
+ */
+#define ERROR_DELAY_JIFFIES (HZ / 10)
+
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@@ -100,6 +107,7 @@ struct snd_usb_midi {
snd_rawmidi_t* rmidi;
struct usb_protocol_ops* usb_protocol_ops;
struct list_head list;
+ struct timer_list error_timer;
struct snd_usb_midi_endpoint {
snd_usb_midi_out_endpoint_t *out;
@@ -141,7 +149,8 @@ struct snd_usb_midi_in_endpoint {
struct usbmidi_in_port {
snd_rawmidi_substream_t* substream;
} ports[0x10];
- int seen_f5;
+ u8 seen_f5;
+ u8 error_resubmit;
int current_port;
};
@@ -167,14 +176,22 @@ static int snd_usbmidi_submit_urb(struct urb* urb, int flags)
*/
static int snd_usbmidi_urb_error(int status)
{
- if (status == -ENOENT)
- return status; /* killed */
- if (status == -EILSEQ ||
- status == -ECONNRESET ||
- status == -ETIMEDOUT)
- return -ENODEV; /* device removed/shutdown */
- snd_printk(KERN_ERR "urb status %d\n", status);
- return 0; /* continue */
+ switch (status) {
+ /* manually unlinked, or device gone */
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ return -ENODEV;
+ /* errors that might occur during unplugging */
+ case -EPROTO: /* EHCI */
+ case -ETIMEDOUT: /* OHCI */
+ case -EILSEQ: /* UHCI */
+ return -EIO;
+ default:
+ snd_printk(KERN_ERR "urb status %d\n", status);
+ return 0; /* continue */
+ }
}
/*
@@ -218,8 +235,15 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
urb->actual_length);
} else {
- if (snd_usbmidi_urb_error(urb->status) < 0)
+ int err = snd_usbmidi_urb_error(urb->status);
+ if (err < 0) {
+ if (err != -ENODEV) {
+ ep->error_resubmit = 1;
+ mod_timer(&ep->umidi->error_timer,
+ jiffies + ERROR_DELAY_JIFFIES);
+ }
return;
+ }
}
if (usb_pipe_needs_resubmit(urb->pipe)) {
@@ -236,8 +260,13 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
ep->urb_active = 0;
spin_unlock(&ep->buffer_lock);
if (urb->status < 0) {
- if (snd_usbmidi_urb_error(urb->status) < 0)
+ int err = snd_usbmidi_urb_error(urb->status);
+ if (err < 0) {
+ if (err != -ENODEV)
+ mod_timer(&ep->umidi->error_timer,
+ jiffies + ERROR_DELAY_JIFFIES);
return;
+ }
}
snd_usbmidi_do_output(ep);
}
@@ -276,6 +305,24 @@ static void snd_usbmidi_out_tasklet(unsigned long data)
snd_usbmidi_do_output(ep);
}
+/* called after transfers had been interrupted due to some USB error */
+static void snd_usbmidi_error_timer(unsigned long data)
+{
+ snd_usb_midi_t *umidi = (snd_usb_midi_t *)data;
+ int i;
+
+ for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+ snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in;
+ if (in && in->error_resubmit) {
+ in->error_resubmit = 0;
+ in->urb->dev = umidi->chip->dev;
+ snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
+ }
+ if (umidi->endpoints[i].out)
+ snd_usbmidi_do_output(umidi->endpoints[i].out);
+ }
+}
+
/* helper function to send static data that may not DMA-able */
static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
const void *data, int len)
@@ -524,16 +571,16 @@ static struct usb_protocol_ops snd_usbmidi_novation_ops = {
};
/*
- * Mark of the Unicorn USB MIDI protocol: raw MIDI.
+ * "raw" protocol: used by the MOTU FastLane.
*/
-static void snd_usbmidi_motu_input(snd_usb_midi_in_endpoint_t* ep,
- uint8_t* buffer, int buffer_length)
+static void snd_usbmidi_raw_input(snd_usb_midi_in_endpoint_t* ep,
+ uint8_t* buffer, int buffer_length)
{
snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
}
-static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep)
+static void snd_usbmidi_raw_output(snd_usb_midi_out_endpoint_t* ep)
{
int count;
@@ -549,9 +596,9 @@ static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep)
ep->urb->transfer_buffer_length = count;
}
-static struct usb_protocol_ops snd_usbmidi_motu_ops = {
- .input = snd_usbmidi_motu_input,
- .output = snd_usbmidi_motu_output,
+static struct usb_protocol_ops snd_usbmidi_raw_ops = {
+ .input = snd_usbmidi_raw_input,
+ .output = snd_usbmidi_raw_output,
};
/*
@@ -594,17 +641,20 @@ static void snd_usbmidi_emagic_finish_out(snd_usb_midi_out_endpoint_t* ep)
static void snd_usbmidi_emagic_input(snd_usb_midi_in_endpoint_t* ep,
uint8_t* buffer, int buffer_length)
{
- /* ignore padding bytes at end of buffer */
- while (buffer_length > 0 && buffer[buffer_length - 1] == 0xff)
- --buffer_length;
+ int i;
+
+ /* FF indicates end of valid data */
+ for (i = 0; i < buffer_length; ++i)
+ if (buffer[i] == 0xff) {
+ buffer_length = i;
+ break;
+ }
/* handle F5 at end of last buffer */
if (ep->seen_f5)
goto switch_port;
while (buffer_length > 0) {
- int i;
-
/* determine size of data until next F5 */
for (i = 0; i < buffer_length; ++i)
if (buffer[i] == 0xf5)
@@ -671,6 +721,10 @@ static void snd_usbmidi_emagic_output(snd_usb_midi_out_endpoint_t* ep)
break;
}
}
+ if (buf_free < ep->max_transfer && buf_free > 0) {
+ *buf = 0xff;
+ --buf_free;
+ }
ep->urb->transfer_buffer_length = ep->max_transfer - buf_free;
}
@@ -765,7 +819,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
{
if (ep->urb) {
- kfree(ep->urb->transfer_buffer);
+ usb_buffer_free(ep->umidi->chip->dev,
+ ep->urb->transfer_buffer_length,
+ ep->urb->transfer_buffer,
+ ep->urb->transfer_dma);
usb_free_urb(ep->urb);
}
kfree(ep);
@@ -799,7 +856,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
else
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
length = usb_maxpacket(umidi->chip->dev, pipe, 0);
- buffer = kmalloc(length, GFP_KERNEL);
+ buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
+ &ep->urb->transfer_dma);
if (!buffer) {
snd_usbmidi_in_endpoint_delete(ep);
return -ENOMEM;
@@ -812,6 +870,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
ep);
+ ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
rep->in = ep;
return 0;
@@ -832,10 +891,10 @@ static unsigned int snd_usbmidi_count_bits(unsigned int x)
*/
static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
{
- if (ep->tasklet.func)
- tasklet_kill(&ep->tasklet);
if (ep->urb) {
- kfree(ep->urb->transfer_buffer);
+ usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
+ ep->urb->transfer_buffer,
+ ep->urb->transfer_dma);
usb_free_urb(ep->urb);
}
kfree(ep);
@@ -867,7 +926,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
/* we never use interrupt output pipes */
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
- buffer = kmalloc(ep->max_transfer, GFP_KERNEL);
+ buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
+ GFP_KERNEL, &ep->urb->transfer_dma);
if (!buffer) {
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
@@ -875,6 +935,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
ep->max_transfer,
snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep);
+ ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
spin_lock_init(&ep->buffer_lock);
tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
@@ -918,8 +979,11 @@ void snd_usbmidi_disconnect(struct list_head* p)
int i;
umidi = list_entry(p, snd_usb_midi_t, list);
+ del_timer_sync(&umidi->error_timer);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
+ if (ep->out)
+ tasklet_kill(&ep->out->tasklet);
if (ep->out && ep->out->urb) {
usb_kill_urb(ep->out->urb);
if (umidi->usb_protocol_ops->finish_out_endpoint)
@@ -1480,6 +1544,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
umidi->iface = iface;
umidi->quirk = quirk;
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
+ init_timer(&umidi->error_timer);
+ umidi->error_timer.function = snd_usbmidi_error_timer;
+ umidi->error_timer.data = (unsigned long)umidi;
/* detect the endpoint(s) to use */
memset(endpoints, 0, sizeof(endpoints));
@@ -1505,8 +1572,8 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
- case QUIRK_MIDI_MOTU:
- umidi->usb_protocol_ops = &snd_usbmidi_motu_ops;
+ case QUIRK_MIDI_RAW:
+ umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
case QUIRK_MIDI_EMAGIC:
@@ -1515,6 +1582,9 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip,
sizeof(snd_usb_midi_endpoint_info_t));
err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
break;
+ case QUIRK_MIDI_MIDITECH:
+ err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+ break;
default:
snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
err = -ENXIO;
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index e73c1c9d3e73..fa7056f5caaf 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -363,7 +363,7 @@ static int get_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int *value
}
/* channel = 0: master, 1 = first channel */
-inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value)
+static inline int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value)
{
return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
}
@@ -399,7 +399,7 @@ static int set_cur_ctl_value(usb_mixer_elem_info_t *cval, int validx, int value)
return set_ctl_value(cval, SET_CUR, validx, value);
}
-inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value)
+static inline int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value)
{
return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
}
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index f5135641b3e2..f74e652a1e51 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -116,6 +116,7 @@ YAMAHA_DEVICE(0x1039, NULL),
YAMAHA_DEVICE(0x103a, NULL),
YAMAHA_DEVICE(0x103b, NULL),
YAMAHA_DEVICE(0x103c, NULL),
+YAMAHA_DEVICE(0x103d, NULL),
YAMAHA_DEVICE(0x2000, "DGP-7"),
YAMAHA_DEVICE(0x2001, "DGP-5"),
YAMAHA_DEVICE(0x2002, NULL),
@@ -1259,7 +1260,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
/* Mark of the Unicorn devices */
{
/* thanks to Robert A. Lerche <ral 'at' msbit.com> */
- USB_DEVICE(0x07fd, 0x0001),
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_PRODUCT |
+ USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
+ .idVendor = 0x07fd,
+ .idProduct = 0x0001,
+ .bDeviceSubClass = 2,
.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
.vendor_name = "MOTU",
.product_name = "Fastlane",
@@ -1268,7 +1274,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = & (const snd_usb_audio_quirk_t[]) {
{
.ifnum = 0,
- .type = QUIRK_MIDI_MOTU
+ .type = QUIRK_MIDI_RAW
},
{
.ifnum = 1,
@@ -1373,6 +1379,25 @@ YAMAHA_DEVICE(0x7010, "UB99"),
},
{
+ USB_DEVICE(0x4752, 0x0011),
+ .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+ .vendor_name = "Miditech",
+ .product_name = "Midistart-2",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_MIDITECH
+ }
+},
+{
+ USB_DEVICE(0x7104, 0x2202),
+ .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+ .vendor_name = "Miditech",
+ .product_name = "MidiStudio-2",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_MIDITECH
+ }
+},
+
+{
/*
* Some USB MIDI devices don't have an audio control interface,
* so we have to grab MIDI streaming interfaces here.
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index bef9b0c142c4..0281a362857a 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -232,8 +232,7 @@ static int snd_usX2Y_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp)
if (err)
return err;
if (dsp->index == 1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4); // give the device some time
+ msleep(250); // give the device some time
err = usX2Y_AsyncSeq04_init(priv);
if (err) {
snd_printk("usX2Y_AsyncSeq04_init error \n");
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index bb2c8e9000c6..d0199c4e5551 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -50,6 +50,7 @@
Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
*/
+#include <linux/delay.h>
#include "usbusx2yaudio.c"
#if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) && USX2Y_NRPACKS == 1)
@@ -520,11 +521,8 @@ static int snd_usX2Y_usbpcm_prepare(snd_pcm_substream_t *substream)
usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
if (atomic_read(&subs->state) < state_PREPARED) {
while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) {
- signed long timeout;
snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
- set_current_state(TASK_INTERRUPTIBLE);
- timeout = schedule_timeout(HZ/100 + 1);
- if (signal_pending(current)) {
+ if (msleep_interruptible(10)) {
err = -ERESTARTSYS;
goto up_prepare_mutex;
}
@@ -626,7 +624,7 @@ static int usX2Y_pcms_lock_check(snd_card_t *card)
for (s = 0; s < 2; ++s) {
snd_pcm_substream_t *substream;
substream = pcm->streams[s].substream;
- if (substream && substream->open_flag)
+ if (substream && substream->ffile != NULL)
err = -EBUSY;
}
}