summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-04-13 11:24:34 +0200
committerTakashi Iwai <tiwai@suse.de>2010-04-13 11:24:34 +0200
commit067e4a5d23422c9e9a0787b7e18fa2457226d999 (patch)
tree550ab9dc96efe513b2ffeafbff6662f8caaa68ef
parent0d0fb0f9c5fddef4a10242fe3337f00f528a3099 (diff)
parent4cf19b848f92641eeb2585949a09eedec57fb53a (diff)
Merge branch 'topic/bkl' into topic/core-cleanup
-rw-r--r--sound/atmel/Kconfig2
-rw-r--r--sound/atmel/ac97c.c355
-rw-r--r--sound/core/info.c4
-rw-r--r--sound/core/pcm_native.c9
-rw-r--r--sound/core/sound.c73
-rw-r--r--sound/pci/ice1712/aureon.c89
-rw-r--r--sound/ppc/tumbler.c12
-rw-r--r--sound/usb/Kconfig1
-rw-r--r--sound/usb/caiaq/control.c99
-rw-r--r--sound/usb/caiaq/device.c8
-rw-r--r--sound/usb/caiaq/device.h24
-rw-r--r--sound/usb/caiaq/input.c162
12 files changed, 633 insertions, 205 deletions
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig
index 6c228a91940..94de43a096f 100644
--- a/sound/atmel/Kconfig
+++ b/sound/atmel/Kconfig
@@ -12,7 +12,7 @@ config SND_ATMEL_AC97C
tristate "Atmel AC97 Controller (AC97C) driver"
select SND_PCM
select SND_AC97_CODEC
- depends on DW_DMAC && AVR32
+ depends on (DW_DMAC && AVR32) || ARCH_AT91
help
ALSA sound driver for the Atmel AC97 controller.
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 0c0f8771656..428121a7e70 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -31,6 +32,10 @@
#include <linux/dw_dmac.h>
+#include <mach/cpu.h>
+#include <mach/hardware.h>
+#include <mach/gpio.h>
+
#include "ac97c.h"
enum {
@@ -63,6 +68,7 @@ struct atmel_ac97c {
u64 cur_format;
unsigned int cur_rate;
unsigned long flags;
+ int playback_period, capture_period;
/* Serialize access to opened variable */
spinlock_t lock;
void __iomem *regs;
@@ -242,10 +248,12 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
- if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
- dw_dma_cyclic_free(chip->dma.tx_chan);
-
+ if (cpu_is_at32ap7000()) {
+ /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+ if (retval == 1)
+ if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.tx_chan);
+ }
/* Set restrictions to params. */
mutex_lock(&opened_mutex);
chip->cur_rate = params_rate(hw_params);
@@ -266,9 +274,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
if (retval < 0)
return retval;
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
- if (retval == 1)
- if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
- dw_dma_cyclic_free(chip->dma.rx_chan);
+ if (cpu_is_at32ap7000()) {
+ if (retval < 0)
+ return retval;
+ /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
+ if (retval == 1)
+ if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.rx_chan);
+ }
/* Set restrictions to params. */
mutex_lock(&opened_mutex);
@@ -282,16 +295,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
- dw_dma_cyclic_free(chip->dma.tx_chan);
+ if (cpu_is_at32ap7000()) {
+ if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.tx_chan);
+ }
return snd_pcm_lib_free_pages(substream);
}
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
- dw_dma_cyclic_free(chip->dma.rx_chan);
+ if (cpu_is_at32ap7000()) {
+ if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_free(chip->dma.rx_chan);
+ }
return snd_pcm_lib_free_pages(substream);
}
@@ -299,9 +316,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ int block_size = frames_to_bytes(runtime, runtime->period_size);
unsigned long word = ac97c_readl(chip, OCA);
int retval;
+ chip->playback_period = 0;
word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -320,11 +339,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
ac97c_writel(chip, OCA, word);
/* configure sample format and size */
- word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+ word = ac97c_readl(chip, CAMR);
+ if (chip->opened <= 1)
+ word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+ else
+ word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
- word |= AC97C_CMR_CEM_LITTLE;
+ if (cpu_is_at32ap7000())
+ word |= AC97C_CMR_CEM_LITTLE;
break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -363,9 +387,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
runtime->rate);
- if (!test_bit(DMA_TX_READY, &chip->flags))
- retval = atmel_ac97c_prepare_dma(chip, substream,
- DMA_TO_DEVICE);
+ if (cpu_is_at32ap7000()) {
+ if (!test_bit(DMA_TX_READY, &chip->flags))
+ retval = atmel_ac97c_prepare_dma(chip, substream,
+ DMA_TO_DEVICE);
+ } else {
+ /* Initialize and start the PDC */
+ writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
+ writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
+ writel(runtime->dma_addr + block_size,
+ chip->regs + ATMEL_PDC_TNPR);
+ writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+ }
return retval;
}
@@ -374,9 +407,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ int block_size = frames_to_bytes(runtime, runtime->period_size);
unsigned long word = ac97c_readl(chip, ICA);
int retval;
+ chip->capture_period = 0;
word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
/* assign channels to AC97C channel A */
@@ -395,11 +430,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
ac97c_writel(chip, ICA, word);
/* configure sample format and size */
- word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+ word = ac97c_readl(chip, CAMR);
+ if (chip->opened <= 1)
+ word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
+ else
+ word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
switch (runtime->format) {
case SNDRV_PCM_FORMAT_S16_LE:
- word |= AC97C_CMR_CEM_LITTLE;
+ if (cpu_is_at32ap7000())
+ word |= AC97C_CMR_CEM_LITTLE;
break;
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -438,9 +478,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
runtime->rate);
- if (!test_bit(DMA_RX_READY, &chip->flags))
- retval = atmel_ac97c_prepare_dma(chip, substream,
- DMA_FROM_DEVICE);
+ if (cpu_is_at32ap7000()) {
+ if (!test_bit(DMA_RX_READY, &chip->flags))
+ retval = atmel_ac97c_prepare_dma(chip, substream,
+ DMA_FROM_DEVICE);
+ } else {
+ /* Initialize and start the PDC */
+ writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
+ writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
+ writel(runtime->dma_addr + block_size,
+ chip->regs + ATMEL_PDC_RNPR);
+ writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
+ }
return retval;
}
@@ -449,7 +498,7 @@ static int
atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
+ unsigned long camr, ptcr = 0;
int retval = 0;
camr = ac97c_readl(chip, CAMR);
@@ -458,15 +507,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- retval = dw_dma_cyclic_start(chip->dma.tx_chan);
- if (retval)
- goto out;
- camr |= AC97C_CMR_CENA;
+ if (cpu_is_at32ap7000()) {
+ retval = dw_dma_cyclic_start(chip->dma.tx_chan);
+ if (retval)
+ goto out;
+ } else {
+ ptcr = ATMEL_PDC_TXTEN;
+ }
+ camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
- dw_dma_cyclic_stop(chip->dma.tx_chan);
+ if (cpu_is_at32ap7000())
+ dw_dma_cyclic_stop(chip->dma.tx_chan);
+ else
+ ptcr |= ATMEL_PDC_TXTDIS;
if (chip->opened <= 1)
camr &= ~AC97C_CMR_CENA;
break;
@@ -476,6 +532,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
}
ac97c_writel(chip, CAMR, camr);
+ if (!cpu_is_at32ap7000())
+ writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out:
return retval;
}
@@ -484,24 +542,32 @@ static int
atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
- unsigned long camr;
+ unsigned long camr, ptcr = 0;
int retval = 0;
camr = ac97c_readl(chip, CAMR);
+ ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- retval = dw_dma_cyclic_start(chip->dma.rx_chan);
- if (retval)
- goto out;
- camr |= AC97C_CMR_CENA;
+ if (cpu_is_at32ap7000()) {
+ retval = dw_dma_cyclic_start(chip->dma.rx_chan);
+ if (retval)
+ goto out;
+ } else {
+ ptcr = ATMEL_PDC_RXTEN;
+ }
+ camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
- dw_dma_cyclic_stop(chip->dma.rx_chan);
+ if (cpu_is_at32ap7000())
+ dw_dma_cyclic_stop(chip->dma.rx_chan);
+ else
+ ptcr |= (ATMEL_PDC_RXTDIS);
if (chip->opened <= 1)
camr &= ~AC97C_CMR_CENA;
break;
@@ -511,6 +577,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
}
ac97c_writel(chip, CAMR, camr);
+ if (!cpu_is_at32ap7000())
+ writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
out:
return retval;
}
@@ -523,7 +591,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
snd_pcm_uframes_t frames;
unsigned long bytes;
- bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+ if (cpu_is_at32ap7000())
+ bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
+ else
+ bytes = readl(chip->regs + ATMEL_PDC_TPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -540,7 +611,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
snd_pcm_uframes_t frames;
unsigned long bytes;
- bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+ if (cpu_is_at32ap7000())
+ bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
+ else
+ bytes = readl(chip->regs + ATMEL_PDC_RPR);
bytes -= runtime->dma_addr;
frames = bytes_to_frames(runtime, bytes);
@@ -578,8 +652,11 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
u32 sr = ac97c_readl(chip, SR);
u32 casr = ac97c_readl(chip, CASR);
u32 cosr = ac97c_readl(chip, COSR);
+ u32 camr = ac97c_readl(chip, CAMR);
if (sr & AC97C_SR_CAEVT) {
+ struct snd_pcm_runtime *runtime;
+ int offset, next_period, block_size;
dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
casr & AC97C_CSR_OVRUN ? " OVRUN" : "",
casr & AC97C_CSR_RXRDY ? " RXRDY" : "",
@@ -587,6 +664,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
casr & AC97C_CSR_TXRDY ? " TXRDY" : "",
!casr ? " NONE" : "");
+ if (!cpu_is_at32ap7000()) {
+ if ((casr & camr) & AC97C_CSR_ENDTX) {
+ runtime = chip->playback_substream->runtime;
+ block_size = frames_to_bytes(runtime,
+ runtime->period_size);
+ chip->playback_period++;
+
+ if (chip->playback_period == runtime->periods)
+ chip->playback_period = 0;
+ next_period = chip->playback_period + 1;
+ if (next_period == runtime->periods)
+ next_period = 0;
+
+ offset = block_size * next_period;
+
+ writel(runtime->dma_addr + offset,
+ chip->regs + ATMEL_PDC_TNPR);
+ writel(block_size / 2,
+ chip->regs + ATMEL_PDC_TNCR);
+
+ snd_pcm_period_elapsed(
+ chip->playback_substream);
+ }
+ if ((casr & camr) & AC97C_CSR_ENDRX) {
+ runtime = chip->capture_substream->runtime;
+ block_size = frames_to_bytes(runtime,
+ runtime->period_size);
+ chip->capture_period++;
+
+ if (chip->capture_period == runtime->periods)
+ chip->capture_period = 0;
+ next_period = chip->capture_period + 1;
+ if (next_period == runtime->periods)
+ next_period = 0;
+
+ offset = block_size * next_period;
+
+ writel(runtime->dma_addr + offset,
+ chip->regs + ATMEL_PDC_RNPR);
+ writel(block_size / 2,
+ chip->regs + ATMEL_PDC_RNCR);
+ snd_pcm_period_elapsed(chip->capture_substream);
+ }
+ }
retval = IRQ_HANDLED;
}
@@ -608,15 +729,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
return retval;
}
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
+ /* Playback */
+ {
+ .exclusive = 1,
+ .r = { {
+ .slots = ((1 << AC97_SLOT_PCM_LEFT)
+ | (1 << AC97_SLOT_PCM_RIGHT)),
+ } },
+ },
+ /* PCM in */
+ {
+ .stream = 1,
+ .exclusive = 1,
+ .r = { {
+ .slots = ((1 << AC97_SLOT_PCM_LEFT)
+ | (1 << AC97_SLOT_PCM_RIGHT)),
+ } }
+ },
+ /* Mic in */
+ {
+ .stream = 1,
+ .exclusive = 1,
+ .r = { {
+ .slots = (1<<AC97_SLOT_MIC),
+ } }
+ },
+};
+
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
{
struct snd_pcm *pcm;
struct snd_pcm_hardware hw = atmel_ac97c_hw;
- int capture, playback, retval;
+ int capture, playback, retval, err;
capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ if (!cpu_is_at32ap7000()) {
+ err = snd_ac97_pcm_assign(chip->ac97_bus,
+ ARRAY_SIZE(at91_ac97_pcm_defs),
+ at91_ac97_pcm_defs);
+ if (err)
+ return err;
+ }
retval = snd_pcm_new(chip->card, chip->card->shortname,
chip->pdev->id, playback, capture, &pcm);
if (retval)
@@ -775,7 +931,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
return -ENXIO;
}
- pclk = clk_get(&pdev->dev, "pclk");
+ if (cpu_is_at32ap7000()) {
+ pclk = clk_get(&pdev->dev, "pclk");
+ } else {
+ pclk = clk_get(&pdev->dev, "ac97_clk");
+ }
+
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
@@ -844,43 +1005,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
goto err_ac97_bus;
}
- if (pdata->rx_dws.dma_dev) {
- struct dw_dma_slave *dws = &pdata->rx_dws;
- dma_cap_mask_t mask;
+ if (cpu_is_at32ap7000()) {
+ if (pdata->rx_dws.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->rx_dws;
+ dma_cap_mask_t mask;
- dws->rx_reg = regs->start + AC97C_CARHR + 2;
+ dws->rx_reg = regs->start + AC97C_CARHR + 2;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
- chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
+ chip->dma.rx_chan = dma_request_channel(mask, filter,
+ dws);
- dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
+ dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
dev_name(&chip->dma.rx_chan->dev->device));
- set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- }
+ set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ }
- if (pdata->tx_dws.dma_dev) {
- struct dw_dma_slave *dws = &pdata->tx_dws;
- dma_cap_mask_t mask;
+ if (pdata->tx_dws.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->tx_dws;
+ dma_cap_mask_t mask;
- dws->tx_reg = regs->start + AC97C_CATHR + 2;
+ dws->tx_reg = regs->start + AC97C_CATHR + 2;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
- chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
+ chip->dma.tx_chan = dma_request_channel(mask, filter,
+ dws);
- dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
+ dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
dev_name(&chip->dma.tx_chan->dev->device));
- set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- }
+ set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ }
- if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
- !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
- dev_dbg(&pdev->dev, "DMA not available\n");
- retval = -ENODEV;
- goto err_dma;
+ if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
+ !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
+ dev_dbg(&pdev->dev, "DMA not available\n");
+ retval = -ENODEV;
+ goto err_dma;
+ }
+ } else {
+ /* Just pretend that we have DMA channel(for at91 i is actually
+ * the PDC) */
+ set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
}
retval = atmel_ac97c_pcm_new(chip);
@@ -897,20 +1067,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
- dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n",
- chip->regs);
+ dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n",
+ chip->regs, irq);
return 0;
err_dma:
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
- dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
- dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
+ if (cpu_is_at32ap7000()) {
+ if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.tx_chan);
+ clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ chip->dma.rx_chan = NULL;
+ chip->dma.tx_chan = NULL;
+ }
err_ac97_bus:
snd_card_set_dev(card, NULL);
@@ -934,10 +1106,12 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg)
struct snd_card *card = platform_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
- if (test_bit(DMA_RX_READY, &chip->flags))
- dw_dma_cyclic_stop(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
- dw_dma_cyclic_stop(chip->dma.tx_chan);
+ if (cpu_is_at32ap7000()) {
+ if (test_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_stop(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_stop(chip->dma.tx_chan);
+ }
clk_disable(chip->pclk);
return 0;
@@ -949,11 +1123,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev)
struct atmel_ac97c *chip = card->private_data;
clk_enable(chip->pclk);
- if (test_bit(DMA_RX_READY, &chip->flags))
- dw_dma_cyclic_start(chip->dma.rx_chan);
- if (test_bit(DMA_TX_READY, &chip->flags))
- dw_dma_cyclic_start(chip->dma.tx_chan);
-
+ if (cpu_is_at32ap7000()) {
+ if (test_bit(DMA_RX_READY, &chip->flags))
+ dw_dma_cyclic_start(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_READY, &chip->flags))
+ dw_dma_cyclic_start(chip->dma.tx_chan);
+ }
return 0;
}
#else
@@ -978,14 +1153,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
iounmap(chip->regs);
free_irq(chip->irq, chip);
- if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
- dma_release_channel(chip->dma.rx_chan);
- if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
- dma_release_channel(chip->dma.tx_chan);
- clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
- clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
- chip->dma.rx_chan = NULL;
- chip->dma.tx_chan = NULL;
+ if (cpu_is_at32ap7000()) {
+ if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.rx_chan);
+ if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
+ dma_release_channel(chip->dma.tx_chan);
+ clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
+ clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+ chip->dma.rx_chan = NULL;
+ chip->dma.tx_chan = NULL;
+ }
snd_card_set_dev(card, NULL);
snd_card_free(card);
diff --git a/sound/core/info.c b/sound/core/info.c
index cc4a53d4b7f..ff968be8167 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -168,7 +168,7 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
data = file->private_data;
entry = data->entry;
- lock_kernel();
+ mutex_lock(&entry->access);
switch (entry->content) {
case SNDRV_INFO_CONTENT_TEXT:
switch (orig) {
@@ -197,7 +197,7 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
}
ret = -ENXIO;
out:
- unlock_kernel();
+ mutex_unlock(&entry->access);
return ret;
}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 87288762403..cadba308776 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3303,18 +3303,13 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
struct snd_pcm_file * pcm_file;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
- int err = -ENXIO;
- lock_kernel();
pcm_file = file->private_data;
substream = pcm_file->substream;
if (PCM_RUNTIME_CHECK(substream))
- goto out;
+ return -ENXIO;
runtime = substream->runtime;
- err = fasync_helper(fd, file, on, &runtime->fasync);
-out:
- unlock_kernel();
- return err;
+ return fasync_helper(fd, file, on, &runtime->fasync);
}
/*
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 563d1967a0a..ac42af42b78 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -120,7 +120,29 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
EXPORT_SYMBOL(snd_lookup_minor_data);
-static int __snd_open(struct inode *inode, struct file *file)
+#ifdef CONFIG_MODULES
+static struct snd_minor *autoload_device(unsigned int minor)
+{
+ int dev;
+ mutex_unlock(&sound_mutex); /* release lock temporarily */
+ dev = SNDRV_MINOR_DEVICE(minor);
+ if (dev == SNDRV_MINOR_CONTROL) {
+ /* /dev/aloadC? */
+ int card = SNDRV_MINOR_CARD(minor);
+ if (snd_cards[card] == NULL)
+ snd_request_card(card);
+ } else if (dev == SNDRV_MINOR_GLOBAL) {
+ /* /dev/aloadSEQ */
+ snd_request_other(minor);
+ }
+ mutex_lock(&sound_mutex); /* reacuire lock */
+ return snd_minors[minor];
+}
+#else /* !CONFIG_MODULES */
+#define autoload_device(minor) NULL
+#endif /* CONFIG_MODULES */
+
+static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
@@ -129,55 +151,36 @@ static int __snd_open(struct inode *inode, struct file *file)
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
+ mutex_lock(&sound_mutex);
mptr = snd_minors[minor];
if (mptr == NULL) {
-#ifdef CONFIG_MODULES
- int dev = SNDRV_MINOR_DEVICE(minor);
- if (dev == SNDRV_MINOR_CONTROL) {
- /* /dev/aloadC? */
- int card = SNDRV_MINOR_CARD(minor);
- if (snd_cards[card] == NULL)
- snd_request_card(card);
- } else if (dev == SNDRV_MINOR_GLOBAL) {
- /* /dev/aloadSEQ */
- snd_request_other(minor);
- }
-#ifndef CONFIG_SND_DYNAMIC_MINORS
- /* /dev/snd/{controlC?,seq} */
- mptr = snd_minors[minor];
- if (mptr == NULL)
-#endif
-#endif
+ mptr = autoload_device(minor);
+ if (!mptr) {
+ mutex_unlock(&sound_mutex);
return -ENODEV;
+ }
}
old_fops = file->f_op;
file->f_op = fops_get(mptr->f_ops);
if (file->f_op == NULL) {
file->f_op = old_fops;
- return -ENODEV;
+ err = -ENODEV;
}
- if (file->f_op->open)
+ mutex_unlock(&sound_mutex);
+ if (err < 0)
+ return err;
+
+ if (file->f_op->open) {
err = file->f_op->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
+ }
}
fops_put(old_fops);
return err;
}
-
-/* BKL pushdown: nasty #ifdef avoidance wrapper */
-static int snd_open(struct inode *inode, struct file *file)
-{
- int ret;
-
- lock_kernel();
- ret = __snd_open(inode, file);
- unlock_kernel();
- return ret;
-}
-
static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 9e66f6d306f..2f6252266a0 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -1956,11 +1956,10 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice)
return 0;
}
-
/*
- * initialize the chip
+ * reset the chip
*/
-static int __devinit aureon_init(struct snd_ice1712 *ice)
+static int aureon_reset(struct snd_ice1712 *ice)
{
static const unsigned short wm_inits_aureon[] = {
/* These come first to reduce init pop noise */
@@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */
(unsigned short)-1
};
- struct aureon_spec *spec;
unsigned int tmp;
const unsigned short *p;
- int err, i;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
- ice->spec = spec;
-
- if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
- ice->num_total_dacs = 6;
- ice->num_total_adcs = 2;
- } else {
- /* aureon 7.1 and prodigy 7.1 */
- ice->num_total_dacs = 8;
- ice->num_total_adcs = 2;
- }
-
- /* to remeber the register values of CS8415 */
- ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
- if (!ice->akm)
- return -ENOMEM;
- ice->akm_codecs = 1;
+ int err;
+ struct aureon_spec *spec = ice->spec;
err = aureon_ac97_init(ice);
if (err != 0)
@@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
/* initialize PCA9554 pin directions & set default input */
aureon_pca9554_write(ice, PCA9554_DIR, 0x00);
aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */
+ return 0;
+}
+
+/*
+ * suspend/resume
+ */
+#ifdef CONFIG_PM
+static int aureon_resume(struct snd_ice1712 *ice)
+{
+ struct aureon_spec *spec = ice->spec;
+ int err, i;
+
+ err = aureon_reset(ice);
+ if (err != 0)
+ return err;
+
+ /* workaround for poking volume with alsamixer after resume:
+ * just set stored volume again */
+ for (i = 0; i < ice->num_total_dacs; i++)
+ wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
+ return 0;
+}
+#endif
+
+/*
+ * initialize the chip
+ */
+static int __devinit aureon_init(struct snd_ice1712 *ice)
+{
+ struct aureon_spec *spec;
+ int i, err;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (!spec)
+ return -ENOMEM;
+ ice->spec = spec;
+
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) {
+ ice->num_total_dacs = 6;
+ ice->num_total_adcs = 2;
+ } else {
+ /* aureon 7.1 and prodigy 7.1 */
+ ice->num_total_dacs = 8;
+ ice->num_total_adcs = 2;
+ }
+
+ /* to remeber the register values of CS8415 */
+ ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
+ if (!ice->akm)
+ return -ENOMEM;
+ ice->akm_codecs = 1;
+
+ err = aureon_reset(ice);
+ if (err != 0)
+ return err;
spec->master[0] = WM_VOL_MUTE;
spec->master[1] = WM_VOL_MUTE;
@@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
}
+#ifdef CONFIG_PM
+ ice->pm_resume = aureon_resume;
+ ice->pm_suspend_enabled = 1;
+#endif
+
return 0;
}
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 789f44f4ac7..20afdf9772e 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -30,6 +30,7 @@
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/string.h>
#include <sound/core.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -46,6 +47,8 @@
#define DBG(fmt...)
#endif
+#define IS_G4DA (of_machine_is_compatible("PowerMac3,4"))
+
/* i2c address for tumbler */
#define TAS_I2C_ADDR 0x34
@@ -243,6 +246,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set volume \n");
return -EINVAL;
}
+ DBG("(I) succeeded to set volume (%u, %u)\n", left_vol, right_vol);
return 0;
}
@@ -353,6 +357,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL;
}
+ DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0;
}
@@ -389,6 +394,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix)
snd_printk(KERN_ERR "failed to set DRC\n");
return -EINVAL;
}
+ DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]);
return 0;
}
@@ -1134,7 +1140,8 @@ static long tumbler_find_device(const char *device, const char *platform,
gp->inactive_val = (*base) ? 0x4 : 0x5;
} else {
const u32 *prop = NULL;
- gp->active_state = 0;
+ gp->active_state = IS_G4DA
+ && !strncmp(device, "keywest-gpio1", 13);
gp->active_val = 0x4;
gp->inactive_val = 0x5;
/* Here are some crude hacks to extract the GPIO polarity and
@@ -1312,6 +1319,9 @@ static int __devinit tumbler_init(struct snd_pmac *chip)
if (irq <= NO_IRQ)
irq = tumbler_find_device("line-output-detect",
NULL, &mix->line_detect, 1);
+ if (IS_G4DA && irq <= NO_IRQ)
+ irq = tumbler_find_device("keywest-gpio16",
+ NULL, &mix->line_detect, 1);
mix->lineout_irq = irq;
tumbler_reset_audio(chip);
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index c570ae3e6d5..c4dcbadd83a 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -65,6 +65,7 @@ config SND_USB_CAIAQ
* Native Instruments Audio 8 DJ
* Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile
+ * Native Instruments Traktor Kontrol X1
To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq.
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index 537102ba6b9..36ed703a741 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
int is_intval = pos & CNT_INTVAL;
- unsigned int id = dev->chip.usb_id;
+ int maxval = 63;
uinfo->count = 1;
pos &= ~CNT_INTVAL;
- if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)
- && (pos == 0)) {
- /* current input mode of A8DJ */
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 2;
- return 0;
- }
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
+ if (pos == 0) {
+ /* current input mode of A8DJ */
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 2;
+ return 0;
+ }
+ break;
- if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)
- && (pos == 0)) {
- /* current input mode of A4DJ */
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
+ if (pos == 0) {
+ /* current input mode of A4DJ */
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+ }
+ break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ maxval = 127;
+ break;
}
if (is_intval) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 64;
+ uinfo->value.integer.max = maxval;
} else {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->value.integer.min = 0;
@@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value;
+ unsigned char cmd = EP1_CMD_WRITE_IO;
- if (dev->chip.usb_id ==
- USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) {
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
/* A4DJ has only one control */
/* do not expose hardware input mode 0 */
dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
@@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol,
return 1;
}
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ cmd = EP1_CMD_DIMM_LEDS;
+ break;
+ }
+
if (pos & CNT_INTVAL) {
dev->control_state[pos & ~CNT_INTVAL]
= ucontrol->value.integer.value[0];
- snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+ snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state));
} else {
if (ucontrol->value.integer.value[0])
@@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
else
dev->control_state[pos / 8] &= ~(1 << (pos % 8));
- snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO,
+ snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state));
}
@@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = {
{ "Current input mode", 0 | CNT_INTVAL }
};
+static struct caiaq_controller kontrolx1_controller[] = {
+ { "LED FX A: ON", 7 | CNT_INTVAL },
+ { "LED FX A: 1", 6 | CNT_INTVAL },
+ { "LED FX A: 2", 5 | CNT_INTVAL },
+ { "LED FX A: 3", 4 | CNT_INTVAL },
+ { "LED FX B: ON", 3 | CNT_INTVAL },
+ { "LED FX B: 1", 2 | CNT_INTVAL },
+ { "LED FX B: 2", 1 | CNT_INTVAL },
+ { "LED FX B: 3", 0 | CNT_INTVAL },
+
+ { "LED Hotcue", 28 | CNT_INTVAL },
+ { "LED Shift (white)", 29 | CNT_INTVAL },
+ { "LED Shift (green)", 30 | CNT_INTVAL },
+
+ { "LED Deck A: FX1", 24 | CNT_INTVAL },
+ { "LED Deck A: FX2", 25 | CNT_INTVAL },
+ { "LED Deck A: IN", 17 | CNT_INTVAL },
+ { "LED Deck A: OUT", 16 | CNT_INTVAL },
+ { "LED Deck A: < BEAT", 19 | CNT_INTVAL },
+ { "LED Deck A: BEAT >", 18 | CNT_INTVAL },
+ { "LED Deck A: CUE/ABS", 21 | CNT_INTVAL },
+ { "LED Deck A: CUP/REL", 20 | CNT_INTVAL },
+ { "LED Deck A: PLAY", 23 | CNT_INTVAL },
+ { "LED Deck A: SYNC", 22 | CNT_INTVAL },
+
+ { "LED Deck B: FX1", 26 | CNT_INTVAL },
+ { "LED Deck B: FX2", 27 | CNT_INTVAL },
+ { "LED Deck B: IN", 15 | CNT_INTVAL },
+ { "LED Deck B: OUT", 14 | CNT_INTVAL },
+ { "LED Deck B: < BEAT", 13 | CNT_INTVAL },
+ { "LED Deck B: BEAT >", 12 | CNT_INTVAL },
+ { "LED Deck B: CUE/ABS", 11 | CNT_INTVAL },
+ { "LED Deck B: CUP/REL", 10 | CNT_INTVAL },
+ { "LED Deck B: PLAY", 9 | CNT_INTVAL },
+ { "LED Deck B: SYNC", 8 | CNT_INTVAL },
+};
+
static int __devinit add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *dev)
{
@@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
ret = add_controls(a8dj_controller,
ARRAY_SIZE(a8dj_controller), dev);
break;
+
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
ret = add_controls(a4dj_controller,
ARRAY_SIZE(a4dj_controller), dev);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ ret = add_controls(kontrolx1_controller,
+ ARRAY_SIZE(kontrolx1_controller), dev);
+ break;
}
return ret;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index afc5aeb6800..80527182767 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 4 DJ},"
"{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O},"
- "{Native Instruments, GuitarRig mobile}");
+ "{Native Instruments, GuitarRig mobile}"
+ "{Native Instruments, Traktor Kontrol X1}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
@@ -128,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_AUDIO2DJ
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = USB_VID_NATIVEINSTRUMENTS,
+ .idProduct = USB_PID_TRAKTORKONTROLX1
+ },
{ /* terminator */ }
};
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index 44e3edf88be..f1117ecc84f 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -5,18 +5,20 @@
#define USB_VID_NATIVEINSTRUMENTS 0x17cc
-#define USB_PID_RIGKONTROL2 0x1969
-#define USB_PID_RIGKONTROL3 0x1940
-#define USB_PID_KORECONTROLLER 0x4711
-#define USB_PID_KORECONTROLLER2 0x4712
-#define USB_PID_AK1 0x0815
-#define USB_PID_AUDIO2DJ 0x041c
-#define USB_PID_AUDIO4DJ 0x0839
-#define USB_PID_AUDIO8DJ 0x1978
-#define USB_PID_SESSIONIO 0x1915
-#define USB_PID_GUITARRIGMOBILE 0x0d8d
+#define USB_PID_RIGKONTROL2 0x1969
+#define USB_PID_RIGKONTROL3 0x1940
+#define USB_PID_KORECONTROLLER 0x4711
+#define USB_PID_KORECONTROLLER2 0x4712
+#define USB_PID_AK1 0x0815
+#define USB_PID_AUDIO2DJ 0x041c
+#define USB_PID_AUDIO4DJ 0x0839
+#define USB_PID_AUDIO8DJ 0x1978
+#define USB_PID_SESSIONIO 0x1915
+#define USB_PID_GUITARRIGMOBILE 0x0d8d
+#define USB_PID_TRAKTORKONTROLX1 0x2305
#define EP1_BUFSIZE 64
+#define EP4_BUFSIZE 512
#define CAIAQ_USB_STR_LEN 0xff
#define MAX_STREAMS 32
@@ -104,6 +106,8 @@ struct snd_usb_caiaqdev {
struct input_dev *input_dev;
char phys[64]; /* physical device path */
unsigned short keycode[64];
+ struct urb *ep4_in_urb;
+ unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif
/* ALSA */
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index a48d309bd94..27ed0bc651a 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
+#include <sound/core.h>
#include <sound/pcm.h>
#include "device.h"
@@ -65,6 +66,8 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5
};
+#define KONTROLX1_INPUTS 40
+
#define DEG90 (range / 2)
#define DEG180 (range)
#define DEG270 (DEG90 + DEG180)
@@ -162,6 +165,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
input_sync(input_dev);
break;
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]);
+ input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
+ input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
+ input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
+ input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
+ input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
+ input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
+ input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
+ input_sync(input_dev);
+ break;
}
}
@@ -201,7 +215,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
}
static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
- char *buf, unsigned int len)
+ unsigned char *buf, unsigned int len)
{
struct input_dev *input_dev = dev->input_dev;
unsigned short *keycode = input_dev->keycode;
@@ -218,15 +232,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
input_report_key(input_dev, keycode[i],
buf[i / 8] & (1 << (i % 8)));
- if (dev->chip.usb_id ==
- USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) ||
- dev->chip.usb_id ==
- USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2))
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
+ break;
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ /* rotary encoders */
+ input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf);
+ input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4);
+ input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf);
+ input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4);
+ break;
+ }
input_sync(input_dev);
}
+static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
+{
+ struct snd_usb_caiaqdev *dev = urb->context;
+ unsigned char *buf = urb->transfer_buffer;
+ int ret;
+
+ if (urb->status || !dev || urb != dev->ep4_in_urb)
+ return;
+
+ if (urb->actual_length < 24)
+ goto requeue;
+
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (buf[0] & 0x3)
+ snd_caiaq_input_read_io(dev, buf + 1, 7);
+
+ if (buf[0] & 0x4)
+ snd_caiaq_input_read_analog(dev, buf + 8, 16);
+
+ break;
+ }
+
+requeue:
+ dev->ep4_in_urb->actual_length = 0;
+ ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC);
+ if (ret < 0)
+ log("unable to submit urb. OOM!?\n");
+}
+
+static int snd_usb_caiaq_input_open(struct input_dev *idev)
+{
+ struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+
+ if (!dev)
+ return -EINVAL;
+
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
+ return -EIO;
+ break;
+ }
+
+ return 0;
+}
+
+static void snd_usb_caiaq_input_close(struct input_dev *idev)
+{
+ struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
+
+ if (!dev)
+ return;
+
+ switch (dev->chip.usb_id) {
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ usb_kill_urb(dev->ep4_in_urb);
+ break;
+ }
+}
+
void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
char *buf,
unsigned int len)
@@ -251,7 +334,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
{
struct usb_device *usb_dev = dev->chip.dev;
struct input_dev *input;
- int i, ret;
+ int i, ret = 0;
input = input_allocate_device();
if (!input)
@@ -265,7 +348,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
usb_to_input_id(usb_dev, &input->id);
input->dev.parent = &usb_dev->dev;
- switch (dev->chip.usb_id) {
+ input_set_drvdata(input, dev);
+
+ switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
@@ -326,25 +411,72 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
+ BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
+ BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
+ BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
+ BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+ BIT_MASK(ABS_Z);
+ input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
+ BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS);
+ for (i = 0; i < KONTROLX1_INPUTS; i++)
+ dev->keycode[i] = BTN_MISC + i;
+ input->keycodemax = KONTROLX1_INPUTS;
+
+ /* analog potentiometers */
+ input_set_abs_params(input, ABS_HAT0X, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT0Y, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT1X, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT1Y, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT2X, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT2Y, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT3X, 0, 4096, 0, 10);
+ input_set_abs_params(input, ABS_HAT3Y, 0, 4096, 0, 10);
+
+ /* rotary encoders */
+ input_set_abs_params(input, ABS_X, 0, 0xf, 0, 1);
+ input_set_abs_params(input, ABS_Y, 0, 0xf, 0, 1);
+ input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1);
+ input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1);
+
+ dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->ep4_in_urb) {
+ ret = -ENOMEM;
+ goto exit_free_idev;
+ }
+
+ usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 0x4),
+ dev->ep4_in_buf, EP4_BUFSIZE,
+ snd_usb_caiaq_ep4_reply_dispatch, dev);
+
+ snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
+
+ break;
default:
/* no input methods supported on this device */
- input_free_device(input);
- return 0;
+ goto exit_free_idev;
}
+ input->open = snd_usb_caiaq_input_open;
+ input->close = snd_usb_caiaq_input_close;
input->keycode = dev->keycode;
input->keycodesize = sizeof(unsigned short);
for (i = 0; i < input->keycodemax; i++)
__set_bit(dev->keycode[i], input->keybit);
ret = input_register_device(input);
- if (ret < 0) {
- input_free_device(input);
- return ret;
- }
+ if (ret < 0)
+ goto exit_free_idev;
dev->input_dev = input;
return 0;
+
+exit_free_idev:
+ input_free_device(input);
+ return ret;
}
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
@@ -352,6 +484,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
if (!dev || !dev->input_dev)
return;
+ usb_kill_urb(dev->ep4_in_urb);
+ usb_free_urb(dev->ep4_in_urb);
+ dev->ep4_in_urb = NULL;
+
input_unregister_device(dev->input_dev);
dev->input_dev = NULL;
}