Merge branch 'topic/core-cleanup' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Thu, 20 May 2010 09:58:57 +0000 (11:58 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 20 May 2010 09:58:57 +0000 (11:58 +0200)
26 files changed:
Documentation/DocBook/writing-an-alsa-driver.tmpl
include/sound/info.h
sound/atmel/Kconfig
sound/atmel/ac97c.c
sound/core/control.c
sound/core/info.c
sound/core/oss/mixer_oss.c
sound/core/oss/pcm_oss.c
sound/core/pcm_native.c
sound/core/rawmidi.c
sound/core/seq/seq_clientmgr.c
sound/core/sound.c
sound/core/timer.c
sound/drivers/opl4/opl4_proc.c
sound/isa/gus/gus_mem_proc.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/emu10k1/emuproc.c
sound/pci/ice1712/aureon.c
sound/pci/mixart/mixart.c
sound/ppc/tumbler.c
sound/usb/Kconfig
sound/usb/caiaq/control.c
sound/usb/caiaq/device.c
sound/usb/caiaq/device.h
sound/usb/caiaq/input.c

index 0d0f7b4..0ba149d 100644 (file)
@@ -5518,34 +5518,41 @@ struct _snd_pcm_runtime {
 ]]>
         </programlisting>
       </informalexample>
+
+      For the raw data, <structfield>size</structfield> field must be
+      set properly.  This specifies the maximum size of the proc file access.
     </para>
 
     <para>
-      The callback is much more complicated than the text-file
-      version. You need to use a low-level I/O functions such as
+      The read/write callbacks of raw mode are more direct than the text mode.
+      You need to use a low-level I/O functions such as
       <function>copy_from/to_user()</function> to transfer the
       data.
 
       <informalexample>
         <programlisting>
 <![CDATA[
-  static long my_file_io_read(struct snd_info_entry *entry,
+  static ssize_t my_file_io_read(struct snd_info_entry *entry,
                               void *file_private_data,
                               struct file *file,
                               char *buf,
-                              unsigned long count,
-                              unsigned long pos)
+                              size_t count,
+                              loff_t pos)
   {
-          long size = count;
-          if (pos + size > local_max_size)
-                  size = local_max_size - pos;
-          if (copy_to_user(buf, local_data + pos, size))
+          if (copy_to_user(buf, local_data + pos, count))
                   return -EFAULT;
-          return size;
+          return count;
   }
 ]]>
         </programlisting>
       </informalexample>
+
+      If the size of the info entry has been set up properly,
+      <structfield>count</structfield> and <structfield>pos</structfield> are
+      guaranteed to fit within 0 and the given size.
+      You don't have to check the range in the callbacks unless any
+      other condition is required.
+
     </para>
 
   </chapter>
index 112e894..4e94cf1 100644 (file)
@@ -51,18 +51,18 @@ struct snd_info_entry_ops {
                    unsigned short mode, void **file_private_data);
        int (*release)(struct snd_info_entry *entry,
                       unsigned short mode, void *file_private_data);
-       long (*read)(struct snd_info_entry *entry, void *file_private_data,
-                    struct file *file, char __user *buf,
-                    unsigned long count, unsigned long pos);
-       long (*write)(struct snd_info_entry *entry, void *file_private_data,
-                     struct file *file, const char __user *buf,
-                     unsigned long count, unsigned long pos);
-       long long (*llseek)(struct snd_info_entry *entry,
-                           void *file_private_data, struct file *file,
-                           long long offset, int orig);
-       unsigned int(*poll)(struct snd_info_entry *entry,
-                           void *file_private_data, struct file *file,
-                           poll_table *wait);
+       ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data,
+                       struct file *file, char __user *buf,
+                       size_t count, loff_t pos);
+       ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data,
+                        struct file *file, const char __user *buf,
+                        size_t count, loff_t pos);
+       loff_t (*llseek)(struct snd_info_entry *entry,
+                        void *file_private_data, struct file *file,
+                        loff_t offset, int orig);
+       unsigned int (*poll)(struct snd_info_entry *entry,
+                            void *file_private_data, struct file *file,
+                            poll_table *wait);
        int (*ioctl)(struct snd_info_entry *entry, void *file_private_data,
                     struct file *file, unsigned int cmd, unsigned long arg);
        int (*mmap)(struct snd_info_entry *entry, void *file_private_data,
index 6c228a9..94de43a 100644 (file)
@@ -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.
 
index 0c0f877..428121a 100644 (file)
@@ -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>
 
 #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);
index 439ce64..070aab4 100644 (file)
@@ -50,6 +50,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
        struct snd_ctl_file *ctl;
        int err;
 
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
+
        card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
        if (!card) {
                err = -ENODEV;
@@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops =
        .read =         snd_ctl_read,
        .open =         snd_ctl_open,
        .release =      snd_ctl_release,
+       .llseek =       no_llseek,
        .poll =         snd_ctl_poll,
        .unlocked_ioctl =       snd_ctl_ioctl,
        .compat_ioctl = snd_ctl_ioctl_compat,
index cc4a53d..b70564e 100644 (file)
@@ -164,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
 {
        struct snd_info_private_data *data;
        struct snd_info_entry *entry;
-       loff_t ret;
+       loff_t ret = -EINVAL, size;
 
        data = file->private_data;
        entry = data->entry;
-       lock_kernel();
-       switch (entry->content) {
-       case SNDRV_INFO_CONTENT_TEXT:
-               switch (orig) {
-               case SEEK_SET:
-                       file->f_pos = offset;
-                       ret = file->f_pos;
-                       goto out;
-               case SEEK_CUR:
-                       file->f_pos += offset;
-                       ret = file->f_pos;
-                       goto out;
-               case SEEK_END:
-               default:
-                       ret = -EINVAL;
-                       goto out;
-               }
+       mutex_lock(&entry->access);
+       if (entry->content == SNDRV_INFO_CONTENT_DATA &&
+           entry->c.ops->llseek) {
+               offset = entry->c.ops->llseek(entry,
+                                             data->file_private_data,
+                                             file, offset, orig);
+               goto out;
+       }
+       if (entry->content == SNDRV_INFO_CONTENT_DATA)
+               size = entry->size;
+       else
+               size = 0;
+       switch (orig) {
+       case SEEK_SET:
                break;
-       case SNDRV_INFO_CONTENT_DATA:
-               if (entry->c.ops->llseek) {
-                       ret = entry->c.ops->llseek(entry,
-                                                   data->file_private_data,
-                                                   file, offset, orig);
+       case SEEK_CUR:
+               offset += file->f_pos;
+               break;
+       case SEEK_END:
+               if (!size)
                        goto out;
-               }
+               offset += size;
                break;
-       }
-       ret = -ENXIO;
-out:
-       unlock_kernel();
+       default:
+               goto out;
+       }
+       if (offset < 0)
+               goto out;
+       if (size && offset > size)
+               offset = size;
+       file->f_pos = offset;
+       ret = offset;
+ out:
+       mutex_unlock(&entry->access);
        return ret;
 }
 
@@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
                        return -EFAULT;
                break;
        case SNDRV_INFO_CONTENT_DATA:
-               if (entry->c.ops->read)
+               if (pos >= entry->size)
+                       return 0;
+               if (entry->c.ops->read) {
+                       size = entry->size - pos;
+                       size = min(count, size);
                        size = entry->c.ops->read(entry,
                                                  data->file_private_data,
-                                                 file, buffer, count, pos);
+                                                 file, buffer, size, pos);
+               }
                break;
        }
        if ((ssize_t) size > 0)
@@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
                size = count;
                break;
        case SNDRV_INFO_CONTENT_DATA:
-               if (entry->c.ops->write)
+               if (entry->c.ops->write && count > 0) {
+                       size_t maxsize = entry->size - pos;
+                       count = min(count, maxsize);
                        size = entry->c.ops->write(entry,
                                                   data->file_private_data,
                                                   file, buffer, count, pos);
+               }
                break;
        }
        if ((ssize_t) size > 0)
index 54e2eb5..f50ebf2 100644 (file)
@@ -43,6 +43,10 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
        struct snd_mixer_oss_file *fmixer;
        int err;
 
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
+
        card = snd_lookup_oss_minor_data(iminor(inode),
                                         SNDRV_OSS_DEVICE_TYPE_MIXER);
        if (card == NULL)
@@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops =
        .owner =        THIS_MODULE,
        .open =         snd_mixer_oss_open,
        .release =      snd_mixer_oss_release,
+       .llseek =       no_llseek,
        .unlocked_ioctl =       snd_mixer_oss_ioctl,
        .compat_ioctl = snd_mixer_oss_ioctl_compat,
 };
index 82d4e33..5c8c7df 100644 (file)
@@ -2379,6 +2379,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
        int nonblock;
        wait_queue_t wait;
 
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
+
        pcm = snd_lookup_oss_minor_data(iminor(inode),
                                        SNDRV_OSS_DEVICE_TYPE_PCM);
        if (pcm == NULL) {
@@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg =
        .write =        snd_pcm_oss_write,
        .open =         snd_pcm_oss_open,
        .release =      snd_pcm_oss_release,
+       .llseek =       no_llseek,
        .poll =         snd_pcm_oss_poll,
        .unlocked_ioctl =       snd_pcm_oss_ioctl,
        .compat_ioctl = snd_pcm_oss_ioctl_compat,
index 20b5982..b9517f3 100644 (file)
@@ -2110,7 +2110,9 @@ static int snd_pcm_open_file(struct file *file,
 static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 {
        struct snd_pcm *pcm;
-
+       int err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
        return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
@@ -2119,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
 static int snd_pcm_capture_open(struct inode *inode, struct file *file)
 {
        struct snd_pcm *pcm;
-
+       int err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
        pcm = snd_lookup_minor_data(iminor(inode),
                                    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
        return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
@@ -3310,18 +3314,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);
 }
 
 /*
@@ -3462,6 +3461,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .aio_write =            snd_pcm_aio_write,
                .open =                 snd_pcm_playback_open,
                .release =              snd_pcm_release,
+               .llseek =               no_llseek,
                .poll =                 snd_pcm_playback_poll,
                .unlocked_ioctl =       snd_pcm_playback_ioctl,
                .compat_ioctl =         snd_pcm_ioctl_compat,
@@ -3475,6 +3475,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
                .aio_read =             snd_pcm_aio_read,
                .open =                 snd_pcm_capture_open,
                .release =              snd_pcm_release,
+               .llseek =               no_llseek,
                .poll =                 snd_pcm_capture_poll,
                .unlocked_ioctl =       snd_pcm_capture_ioctl,
                .compat_ioctl =         snd_pcm_ioctl_compat,
index 0f5a194..eb68326 100644 (file)
@@ -376,6 +376,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) 
                return -EINVAL;         /* invalid combination */
 
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
+
        if (maj == snd_major) {
                rmidi = snd_lookup_minor_data(iminor(inode),
                                              SNDRV_DEVICE_TYPE_RAWMIDI);
@@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops =
        .write =        snd_rawmidi_write,
        .open =         snd_rawmidi_open,
        .release =      snd_rawmidi_release,
+       .llseek =       no_llseek,
        .poll =         snd_rawmidi_poll,
        .unlocked_ioctl =       snd_rawmidi_ioctl,
        .compat_ioctl = snd_rawmidi_ioctl_compat,
index 48eca9f..99a485f 100644 (file)
@@ -318,6 +318,11 @@ static int snd_seq_open(struct inode *inode, struct file *file)
        int c, mode;                    /* client id */
        struct snd_seq_client *client;
        struct snd_seq_user_client *user;
+       int err;
+
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
 
        if (mutex_lock_interruptible(&register_mutex))
                return -ERESTARTSYS;
@@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops =
        .write =        snd_seq_write,
        .open =         snd_seq_open,
        .release =      snd_seq_release,
+       .llseek =       no_llseek,
        .poll =         snd_seq_poll,
        .unlocked_ioctl =       snd_seq_ioctl,
        .compat_ioctl = snd_seq_ioctl_compat,
index 563d196..ac42af4 100644 (file)
@@ -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,
index 5040c7b..13afb60 100644 (file)
@@ -1238,6 +1238,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
 static int snd_timer_user_open(struct inode *inode, struct file *file)
 {
        struct snd_timer_user *tu;
+       int err;
+
+       err = nonseekable_open(inode, file);
+       if (err < 0)
+               return err;
 
        tu = kzalloc(sizeof(*tu), GFP_KERNEL);
        if (tu == NULL)
@@ -1922,6 +1927,7 @@ static const struct file_operations snd_timer_f_ops =
        .read =         snd_timer_user_read,
        .open =         snd_timer_user_open,
        .release =      snd_timer_user_release,
+       .llseek =       no_llseek,
        .poll =         snd_timer_user_poll,
        .unlocked_ioctl =       snd_timer_user_ioctl,
        .compat_ioctl = snd_timer_user_ioctl_compat,
index 1679300..df850b8 100644 (file)
@@ -49,77 +49,45 @@ static int snd_opl4_mem_proc_release(struct snd_info_entry *entry,
        return 0;
 }
 
-static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data,
-                                  struct file *file, char __user *_buf,
-                                  unsigned long count, unsigned long pos)
+static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry,
+                                     void *file_private_data,
+                                     struct file *file, char __user *_buf,
+                                     size_t count, loff_t pos)
 {
        struct snd_opl4 *opl4 = entry->private_data;
-       long size;
        char* buf;
 
-       size = count;
-       if (pos + size > entry->size)
-               size = entry->size - pos;
-       if (size > 0) {
-               buf = vmalloc(size);
-               if (!buf)
-                       return -ENOMEM;
-               snd_opl4_read_memory(opl4, buf, pos, size);
-               if (copy_to_user(_buf, buf, size)) {
-                       vfree(buf);
-                       return -EFAULT;
-               }
+       buf = vmalloc(count);
+       if (!buf)
+               return -ENOMEM;
+       snd_opl4_read_memory(opl4, buf, pos, count);
+       if (copy_to_user(_buf, buf, count)) {
                vfree(buf);
-               return size;
+               return -EFAULT;
        }
-       return 0;
+       vfree(buf);
+       return count;
 }
 
-static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data,
-                                   struct file *file, const char __user *_buf,
-                                   unsigned long count, unsigned long pos)
+static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry,
+                                      void *file_private_data,
+                                      struct file *file,
+                                      const char __user *_buf,
+                                      size_t count, loff_t pos)
 {
        struct snd_opl4 *opl4 = entry->private_data;
-       long size;
        char *buf;
 
-       size = count;
-       if (pos + size > entry->size)
-               size = entry->size - pos;
-       if (size > 0) {
-               buf = vmalloc(size);
-               if (!buf)
-                       return -ENOMEM;
-               if (copy_from_user(buf, _buf, size)) {
-                       vfree(buf);
-                       return -EFAULT;
-               }
-               snd_opl4_write_memory(opl4, buf, pos, size);
+       buf = vmalloc(count);
+       if (!buf)
+               return -ENOMEM;
+       if (copy_from_user(buf, _buf, count)) {
                vfree(buf);
-               return size;
-       }
-       return 0;
-}
-
-static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data,
-                                         struct file *file, long long offset, int orig)
-{
-       switch (orig) {
-       case SEEK_SET:
-               file->f_pos = offset;
-               break;
-       case SEEK_CUR:
-               file->f_pos += offset;
-               break;
-       case SEEK_END: /* offset is negative */
-               file->f_pos = entry->size + offset;
-               break;
-       default:
-               return -EINVAL;
+               return -EFAULT;
        }
-       if (file->f_pos > entry->size)
-               file->f_pos = entry->size;
-       return file->f_pos;
+       snd_opl4_write_memory(opl4, buf, pos, count);
+       vfree(buf);
+       return count;
 }
 
 static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
@@ -127,7 +95,6 @@ static struct snd_info_entry_ops snd_opl4_mem_proc_ops = {
        .release = snd_opl4_mem_proc_release,
        .read = snd_opl4_mem_proc_read,
        .write = snd_opl4_mem_proc_write,
-       .llseek = snd_opl4_mem_proc_llseek,
 };
 
 int snd_opl4_create_proc(struct snd_opl4 *opl4)
index 2803e22..2ccb3fa 100644 (file)
@@ -31,52 +31,21 @@ struct gus_proc_private {
        struct snd_gus_card * gus;
 };
 
-static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data,
-                                 struct file *file, char __user *buf,
-                                 unsigned long count, unsigned long pos)
+static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry,
+                                    void *file_private_data,
+                                    struct file *file, char __user *buf,
+                                    size_t count, loff_t pos)
 {
-       long size;
        struct gus_proc_private *priv = entry->private_data;
        struct snd_gus_card *gus = priv->gus;
        int err;
 
-       size = count;
-       if (pos + size > priv->size)
-               size = (long)priv->size - pos;
-       if (size > 0) {
-               if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0)
-                       return err;
-               return size;
-       }
-       return 0;
+       err = snd_gus_dram_read(gus, buf, pos, count, priv->rom);
+       if (err < 0)
+               return err;
+       return count;
 }                      
 
-static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry,
-                                       void *private_file_data,
-                                       struct file *file,
-                                       long long offset,
-                                       int orig)
-{
-       struct gus_proc_private *priv = entry->private_data;
-
-       switch (orig) {
-       case SEEK_SET:
-               file->f_pos = offset;
-               break;
-       case SEEK_CUR:
-               file->f_pos += offset;
-               break;
-       case SEEK_END: /* offset is negative */
-               file->f_pos = priv->size + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if (file->f_pos > priv->size)
-               file->f_pos = priv->size;
-       return file->f_pos;
-}
-
 static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
 {
        struct gus_proc_private *priv = entry->private_data;
@@ -85,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry)
 
 static struct snd_info_entry_ops snd_gf1_mem_proc_ops = {
        .read = snd_gf1_mem_proc_dump,
-       .llseek = snd_gf1_mem_proc_llseek,
 };
 
 int snd_gf1_mem_proc_init(struct snd_gus_card * gus)
index 9edc650..6772070 100644 (file)
@@ -1139,40 +1139,28 @@ static void snd_cs4281_proc_read(struct snd_info_entry *entry,
        snd_iprintf(buffer, "Spurious end IRQs    : %u\n", chip->spurious_dtc_irq);
 }
 
-static long snd_cs4281_BA0_read(struct snd_info_entry *entry,
-                               void *file_private_data,
-                               struct file *file, char __user *buf,
-                               unsigned long count, unsigned long pos)
+static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry,
+                                  void *file_private_data,
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t pos)
 {
-       long size;
        struct cs4281 *chip = entry->private_data;
        
-       size = count;
-       if (pos + size > CS4281_BA0_SIZE)
-               size = (long)CS4281_BA0_SIZE - pos;
-       if (size > 0) {
-               if (copy_to_user_fromio(buf, chip->ba0 + pos, size))
-                       return -EFAULT;
-       }
-       return size;
+       if (copy_to_user_fromio(buf, chip->ba0 + pos, count))
+               return -EFAULT;
+       return count;
 }
 
-static long snd_cs4281_BA1_read(struct snd_info_entry *entry,
-                               void *file_private_data,
-                               struct file *file, char __user *buf,
-                               unsigned long count, unsigned long pos)
+static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry,
+                                  void *file_private_data,
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t pos)
 {
-       long size;
        struct cs4281 *chip = entry->private_data;
        
-       size = count;
-       if (pos + size > CS4281_BA1_SIZE)
-               size = (long)CS4281_BA1_SIZE - pos;
-       if (size > 0) {
-               if (copy_to_user_fromio(buf, chip->ba1 + pos, size))
-                       return -EFAULT;
-       }
-       return size;
+       if (copy_to_user_fromio(buf, chip->ba1 + pos, count))
+               return -EFAULT;
+       return count;
 }
 
 static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = {
index 3f99a5e..aad3708 100644 (file)
@@ -2657,21 +2657,16 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { }
  *  proc interface
  */
 
-static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data,
-                              struct file *file, char __user *buf,
-                              unsigned long count, unsigned long pos)
+static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry,
+                                 void *file_private_data,
+                                 struct file *file, char __user *buf,
+                                 size_t count, loff_t pos)
 {
-       long size;
        struct snd_cs46xx_region *region = entry->private_data;
        
-       size = count;
-       if (pos + (size_t)size > region->size)
-               size = region->size - pos;
-       if (size > 0) {
-               if (copy_to_user_fromio(buf, region->remap_addr + pos, size))
-                       return -EFAULT;
-       }
-       return size;
+       if (copy_to_user_fromio(buf, region->remap_addr + pos, count))
+               return -EFAULT;
+       return count;
 }
 
 static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = {
index baa7cd5..bc38dd4 100644 (file)
@@ -341,15 +341,17 @@ static void snd_emu10k1_proc_acode_read(struct snd_info_entry *entry,
 #define TOTAL_SIZE_CODE                (0x200*8)
 #define A_TOTAL_SIZE_CODE      (0x400*8)
 
-static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
-                                   void *file_private_data,
-                                   struct file *file, char __user *buf,
-                                   unsigned long count, unsigned long pos)
+static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
+                                      void *file_private_data,
+                                      struct file *file, char __user *buf,
+                                      size_t count, loff_t pos)
 {
-       long size;
        struct snd_emu10k1 *emu = entry->private_data;
        unsigned int offset;
        int tram_addr = 0;
+       unsigned int *tmp;
+       long res;
+       unsigned int idx;
        
        if (!strcmp(entry->name, "fx8010_tram_addr")) {
                offset = TANKMEMADDRREGBASE;
@@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry,
        } else {
                offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE;
        }
-       size = count;
-       if (pos + size > entry->size)
-               size = (long)entry->size - pos;
-       if (size > 0) {
-               unsigned int *tmp;
-               long res;
-               unsigned int idx;
-               if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL)
-                       return -ENOMEM;
-               for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++)
-                       if (tram_addr && emu->audigy) {
-                               tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11;
-                               tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
-                       } else 
-                               tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
-               if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size))
-                       res = -EFAULT;
-               else {
-                       res = size;
+
+       tmp = kmalloc(count + 8, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+       for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) {
+               unsigned int val;
+               val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0);
+               if (tram_addr && emu->audigy) {
+                       val >>= 11;
+                       val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20;
                }
-               kfree(tmp);
-               return res;
+               tmp[idx] = val;
        }
-       return 0;
+       if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count))
+               res = -EFAULT;
+       else
+               res = count;
+       kfree(tmp);
+       return res;
 }
 
 static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, 
index 9e66f6d..2f62522 100644 (file)
@@ -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;
 }
 
index 3be8f97..6c3fd4d 100644 (file)
@@ -1102,73 +1102,17 @@ static int snd_mixart_free(struct mixart_mgr *mgr)
 /*
  * proc interface
  */
-static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry,
-                                      void *private_file_data,
-                                      struct file *file,
-                                      long long offset,
-                                      int orig)
-{
-       offset = offset & ~3; /* 4 bytes aligned */
-
-       switch(orig) {
-       case SEEK_SET:
-               file->f_pos = offset;
-               break;
-       case SEEK_CUR:
-               file->f_pos += offset;
-               break;
-       case SEEK_END: /* offset is negative */
-               file->f_pos = MIXART_BA0_SIZE + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if(file->f_pos > MIXART_BA0_SIZE)
-               file->f_pos = MIXART_BA0_SIZE;
-       return file->f_pos;
-}
-
-static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry,
-                                      void *private_file_data,
-                                      struct file *file,
-                                      long long offset,
-                                      int orig)
-{
-       offset = offset & ~3; /* 4 bytes aligned */
-
-       switch(orig) {
-       case SEEK_SET:
-               file->f_pos = offset;
-               break;
-       case SEEK_CUR:
-               file->f_pos += offset;
-               break;
-       case SEEK_END: /* offset is negative */
-               file->f_pos = MIXART_BA1_SIZE + offset;
-               break;
-       default:
-               return -EINVAL;
-       }
-       if(file->f_pos > MIXART_BA1_SIZE)
-               file->f_pos = MIXART_BA1_SIZE;
-       return file->f_pos;
-}
 
 /*
   mixart_BA0 proc interface for BAR 0 - read callback
  */
-static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private_data,
-                               struct file *file, char __user *buf,
-                               unsigned long count, unsigned long pos)
+static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry,
+                                  void *file_private_data,
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t pos)
 {
        struct mixart_mgr *mgr = entry->private_data;
-       unsigned long maxsize;
 
-       if (pos >= MIXART_BA0_SIZE)
-               return 0;
-       maxsize = MIXART_BA0_SIZE - pos;
-       if (count > maxsize)
-               count = maxsize;
        count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
        if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count))
                return -EFAULT;
@@ -1178,18 +1122,13 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private
 /*
   mixart_BA1 proc interface for BAR 1 - read callback
  */
-static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private_data,
-                               struct file *file, char __user *buf,
-                               unsigned long count, unsigned long pos)
+static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry,
+                                  void *file_private_data,
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t pos)
 {
        struct mixart_mgr *mgr = entry->private_data;
-       unsigned long maxsize;
 
-       if (pos > MIXART_BA1_SIZE)
-               return 0;
-       maxsize = MIXART_BA1_SIZE - pos;
-       if (count > maxsize)
-               count = maxsize;
        count = count & ~3; /* make sure the read size is a multiple of 4 bytes */
        if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count))
                return -EFAULT;
@@ -1198,12 +1137,10 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private
 
 static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = {
        .read   = snd_mixart_BA0_read,
-       .llseek = snd_mixart_BA0_llseek
 };
 
 static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = {
        .read   = snd_mixart_BA1_read,
-       .llseek = snd_mixart_BA1_llseek
 };
 
 
index 789f44f..20afdf9 100644 (file)
@@ -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);
index c570ae3..c4dcbad 100644 (file)
@@ -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.
index 537102b..36ed703 100644 (file)
@@ -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;
index afc5aeb..8052718 100644 (file)
@@ -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 */ }
 };
 
index 44e3edf..f1117ec 100644 (file)
@@ -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 */
index a48d309..27ed0bc 100644 (file)
@@ -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;
 }