diff options
| author | Takashi Iwai <tiwai@suse.de> | 2010-05-20 11:58:57 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-05-20 11:58:57 +0200 | 
| commit | 3374cd1abd478f767aaedf2c21d109596ff0fe72 (patch) | |
| tree | 46b00a571ba5d86373bd9054fdccc5dc6e28e42f | |
| parent | e40152ee1e1c7a63f4777791863215e3faa37a86 (diff) | |
| parent | 670ff6abd6caff406b217f8a828d6c03656535d8 (diff) | |
| download | olio-linux-3.10-3374cd1abd478f767aaedf2c21d109596ff0fe72.tar.xz olio-linux-3.10-3374cd1abd478f767aaedf2c21d109596ff0fe72.zip  | |
Merge branch 'topic/core-cleanup' into for-linus
| -rw-r--r-- | Documentation/DocBook/writing-an-alsa-driver.tmpl | 27 | ||||
| -rw-r--r-- | include/sound/info.h | 24 | ||||
| -rw-r--r-- | sound/atmel/Kconfig | 2 | ||||
| -rw-r--r-- | sound/atmel/ac97c.c | 355 | ||||
| -rw-r--r-- | sound/core/control.c | 5 | ||||
| -rw-r--r-- | sound/core/info.c | 72 | ||||
| -rw-r--r-- | sound/core/oss/mixer_oss.c | 5 | ||||
| -rw-r--r-- | sound/core/oss/pcm_oss.c | 5 | ||||
| -rw-r--r-- | sound/core/pcm_native.c | 19 | ||||
| -rw-r--r-- | sound/core/rawmidi.c | 5 | ||||
| -rw-r--r-- | sound/core/seq/seq_clientmgr.c | 6 | ||||
| -rw-r--r-- | sound/core/sound.c | 73 | ||||
| -rw-r--r-- | sound/core/timer.c | 6 | ||||
| -rw-r--r-- | sound/drivers/opl4/opl4_proc.c | 83 | ||||
| -rw-r--r-- | sound/isa/gus/gus_mem_proc.c | 48 | ||||
| -rw-r--r-- | sound/pci/cs4281.c | 40 | ||||
| -rw-r--r-- | sound/pci/cs46xx/cs46xx_lib.c | 19 | ||||
| -rw-r--r-- | sound/pci/emu10k1/emuproc.c | 51 | ||||
| -rw-r--r-- | sound/pci/ice1712/aureon.c | 89 | ||||
| -rw-r--r-- | sound/pci/mixart/mixart.c | 79 | ||||
| -rw-r--r-- | sound/ppc/tumbler.c | 12 | ||||
| -rw-r--r-- | sound/usb/Kconfig | 1 | ||||
| -rw-r--r-- | sound/usb/caiaq/control.c | 99 | ||||
| -rw-r--r-- | sound/usb/caiaq/device.c | 8 | ||||
| -rw-r--r-- | sound/usb/caiaq/device.h | 24 | ||||
| -rw-r--r-- | sound/usb/caiaq/input.c | 162 | 
26 files changed, 828 insertions, 491 deletions
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 0d0f7b4d4b1..0ba149de260 100644 --- a/Documentation/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl @@ -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> diff --git a/include/sound/info.h b/include/sound/info.h index 112e8949e1a..4e94cf1ff76 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -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, 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/control.c b/sound/core/control.c index 439ce64f9d8..070aab49019 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -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, diff --git a/sound/core/info.c b/sound/core/info.c index cc4a53d4b7f..b70564ed8b3 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -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; +	default: +		goto out;  	} -	ret = -ENXIO; -out: -	unlock_kernel(); +	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) diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 54e2eb56e4c..f50ebf20df9 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -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,  }; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 82d4e3329b3..5c8c7dff8ed 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -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, diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 20b5982c996..b9517f38073 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -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, diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f5a194695d..eb68326c37d 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -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, diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 48eca9ff9ee..99a485f1364 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -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(®ister_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, 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/core/timer.c b/sound/core/timer.c index 5040c7b862f..13afb60999b 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -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, diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index 1679300b758..df850b8830a 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c @@ -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) diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 2803e227aec..2ccb3fadd7b 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -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) diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9edc65059e3..6772070ed49 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -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 = { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 3f99a5e8528..aad37082cb6 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -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 = { diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index baa7cd508cd..bc38dd4d071 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -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,  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/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 3be8f97c8bc..6c3fd4d1c49 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -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  }; 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;  }  |