diff options
| -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 | 74 | ||||
| -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, 829 insertions, 492 deletions
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl index 0d0f7b4d4b1a..0ba149de2608 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 { | |||
| 5518 | ]]> | 5518 | ]]> |
| 5519 | </programlisting> | 5519 | </programlisting> |
| 5520 | </informalexample> | 5520 | </informalexample> |
| 5521 | |||
| 5522 | For the raw data, <structfield>size</structfield> field must be | ||
| 5523 | set properly. This specifies the maximum size of the proc file access. | ||
| 5521 | </para> | 5524 | </para> |
| 5522 | 5525 | ||
| 5523 | <para> | 5526 | <para> |
| 5524 | The callback is much more complicated than the text-file | 5527 | The read/write callbacks of raw mode are more direct than the text mode. |
| 5525 | version. You need to use a low-level I/O functions such as | 5528 | You need to use a low-level I/O functions such as |
| 5526 | <function>copy_from/to_user()</function> to transfer the | 5529 | <function>copy_from/to_user()</function> to transfer the |
| 5527 | data. | 5530 | data. |
| 5528 | 5531 | ||
| 5529 | <informalexample> | 5532 | <informalexample> |
| 5530 | <programlisting> | 5533 | <programlisting> |
| 5531 | <![CDATA[ | 5534 | <![CDATA[ |
| 5532 | static long my_file_io_read(struct snd_info_entry *entry, | 5535 | static ssize_t my_file_io_read(struct snd_info_entry *entry, |
| 5533 | void *file_private_data, | 5536 | void *file_private_data, |
| 5534 | struct file *file, | 5537 | struct file *file, |
| 5535 | char *buf, | 5538 | char *buf, |
| 5536 | unsigned long count, | 5539 | size_t count, |
| 5537 | unsigned long pos) | 5540 | loff_t pos) |
| 5538 | { | 5541 | { |
| 5539 | long size = count; | 5542 | if (copy_to_user(buf, local_data + pos, count)) |
| 5540 | if (pos + size > local_max_size) | ||
| 5541 | size = local_max_size - pos; | ||
| 5542 | if (copy_to_user(buf, local_data + pos, size)) | ||
| 5543 | return -EFAULT; | 5543 | return -EFAULT; |
| 5544 | return size; | 5544 | return count; |
| 5545 | } | 5545 | } |
| 5546 | ]]> | 5546 | ]]> |
| 5547 | </programlisting> | 5547 | </programlisting> |
| 5548 | </informalexample> | 5548 | </informalexample> |
| 5549 | |||
| 5550 | If the size of the info entry has been set up properly, | ||
| 5551 | <structfield>count</structfield> and <structfield>pos</structfield> are | ||
| 5552 | guaranteed to fit within 0 and the given size. | ||
| 5553 | You don't have to check the range in the callbacks unless any | ||
| 5554 | other condition is required. | ||
| 5555 | |||
| 5549 | </para> | 5556 | </para> |
| 5550 | 5557 | ||
| 5551 | </chapter> | 5558 | </chapter> |
diff --git a/include/sound/info.h b/include/sound/info.h index 112e8949e1a7..4e94cf1ff762 100644 --- a/include/sound/info.h +++ b/include/sound/info.h | |||
| @@ -51,18 +51,18 @@ struct snd_info_entry_ops { | |||
| 51 | unsigned short mode, void **file_private_data); | 51 | unsigned short mode, void **file_private_data); |
| 52 | int (*release)(struct snd_info_entry *entry, | 52 | int (*release)(struct snd_info_entry *entry, |
| 53 | unsigned short mode, void *file_private_data); | 53 | unsigned short mode, void *file_private_data); |
| 54 | long (*read)(struct snd_info_entry *entry, void *file_private_data, | 54 | ssize_t (*read)(struct snd_info_entry *entry, void *file_private_data, |
| 55 | struct file *file, char __user *buf, | 55 | struct file *file, char __user *buf, |
| 56 | unsigned long count, unsigned long pos); | 56 | size_t count, loff_t pos); |
| 57 | long (*write)(struct snd_info_entry *entry, void *file_private_data, | 57 | ssize_t (*write)(struct snd_info_entry *entry, void *file_private_data, |
| 58 | struct file *file, const char __user *buf, | 58 | struct file *file, const char __user *buf, |
| 59 | unsigned long count, unsigned long pos); | 59 | size_t count, loff_t pos); |
| 60 | long long (*llseek)(struct snd_info_entry *entry, | 60 | loff_t (*llseek)(struct snd_info_entry *entry, |
| 61 | void *file_private_data, struct file *file, | 61 | void *file_private_data, struct file *file, |
| 62 | long long offset, int orig); | 62 | loff_t offset, int orig); |
| 63 | unsigned int(*poll)(struct snd_info_entry *entry, | 63 | unsigned int (*poll)(struct snd_info_entry *entry, |
| 64 | void *file_private_data, struct file *file, | 64 | void *file_private_data, struct file *file, |
| 65 | poll_table *wait); | 65 | poll_table *wait); |
| 66 | int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, | 66 | int (*ioctl)(struct snd_info_entry *entry, void *file_private_data, |
| 67 | struct file *file, unsigned int cmd, unsigned long arg); | 67 | struct file *file, unsigned int cmd, unsigned long arg); |
| 68 | int (*mmap)(struct snd_info_entry *entry, void *file_private_data, | 68 | int (*mmap)(struct snd_info_entry *entry, void *file_private_data, |
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig index 6c228a91940d..94de43a096f1 100644 --- a/sound/atmel/Kconfig +++ b/sound/atmel/Kconfig | |||
| @@ -12,7 +12,7 @@ config SND_ATMEL_AC97C | |||
| 12 | tristate "Atmel AC97 Controller (AC97C) driver" | 12 | tristate "Atmel AC97 Controller (AC97C) driver" |
| 13 | select SND_PCM | 13 | select SND_PCM |
| 14 | select SND_AC97_CODEC | 14 | select SND_AC97_CODEC |
| 15 | depends on DW_DMAC && AVR32 | 15 | depends on (DW_DMAC && AVR32) || ARCH_AT91 |
| 16 | help | 16 | help |
| 17 | ALSA sound driver for the Atmel AC97 controller. | 17 | ALSA sound driver for the Atmel AC97 controller. |
| 18 | 18 | ||
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 0c0f8771656a..428121a7e705 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 14 | #include <linux/dmaengine.h> | 14 | #include <linux/dmaengine.h> |
| 15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
| 16 | #include <linux/atmel_pdc.h> | ||
| 16 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 17 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| @@ -31,6 +32,10 @@ | |||
| 31 | 32 | ||
| 32 | #include <linux/dw_dmac.h> | 33 | #include <linux/dw_dmac.h> |
| 33 | 34 | ||
| 35 | #include <mach/cpu.h> | ||
| 36 | #include <mach/hardware.h> | ||
| 37 | #include <mach/gpio.h> | ||
| 38 | |||
| 34 | #include "ac97c.h" | 39 | #include "ac97c.h" |
| 35 | 40 | ||
| 36 | enum { | 41 | enum { |
| @@ -63,6 +68,7 @@ struct atmel_ac97c { | |||
| 63 | u64 cur_format; | 68 | u64 cur_format; |
| 64 | unsigned int cur_rate; | 69 | unsigned int cur_rate; |
| 65 | unsigned long flags; | 70 | unsigned long flags; |
| 71 | int playback_period, capture_period; | ||
| 66 | /* Serialize access to opened variable */ | 72 | /* Serialize access to opened variable */ |
| 67 | spinlock_t lock; | 73 | spinlock_t lock; |
| 68 | void __iomem *regs; | 74 | void __iomem *regs; |
| @@ -242,10 +248,12 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream, | |||
| 242 | if (retval < 0) | 248 | if (retval < 0) |
| 243 | return retval; | 249 | return retval; |
| 244 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ | 250 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ |
| 245 | if (retval == 1) | 251 | if (cpu_is_at32ap7000()) { |
| 246 | if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) | 252 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ |
| 247 | dw_dma_cyclic_free(chip->dma.tx_chan); | 253 | if (retval == 1) |
| 248 | 254 | if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) | |
| 255 | dw_dma_cyclic_free(chip->dma.tx_chan); | ||
| 256 | } | ||
| 249 | /* Set restrictions to params. */ | 257 | /* Set restrictions to params. */ |
| 250 | mutex_lock(&opened_mutex); | 258 | mutex_lock(&opened_mutex); |
| 251 | chip->cur_rate = params_rate(hw_params); | 259 | chip->cur_rate = params_rate(hw_params); |
| @@ -266,9 +274,14 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, | |||
| 266 | if (retval < 0) | 274 | if (retval < 0) |
| 267 | return retval; | 275 | return retval; |
| 268 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ | 276 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ |
| 269 | if (retval == 1) | 277 | if (cpu_is_at32ap7000()) { |
| 270 | if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) | 278 | if (retval < 0) |
| 271 | dw_dma_cyclic_free(chip->dma.rx_chan); | 279 | return retval; |
| 280 | /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */ | ||
| 281 | if (retval == 1) | ||
| 282 | if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) | ||
| 283 | dw_dma_cyclic_free(chip->dma.rx_chan); | ||
| 284 | } | ||
| 272 | 285 | ||
| 273 | /* Set restrictions to params. */ | 286 | /* Set restrictions to params. */ |
| 274 | mutex_lock(&opened_mutex); | 287 | mutex_lock(&opened_mutex); |
| @@ -282,16 +295,20 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream, | |||
| 282 | static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) | 295 | static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream) |
| 283 | { | 296 | { |
| 284 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 297 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 285 | if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) | 298 | if (cpu_is_at32ap7000()) { |
| 286 | dw_dma_cyclic_free(chip->dma.tx_chan); | 299 | if (test_and_clear_bit(DMA_TX_READY, &chip->flags)) |
| 300 | dw_dma_cyclic_free(chip->dma.tx_chan); | ||
| 301 | } | ||
| 287 | return snd_pcm_lib_free_pages(substream); | 302 | return snd_pcm_lib_free_pages(substream); |
| 288 | } | 303 | } |
| 289 | 304 | ||
| 290 | static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) | 305 | static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream) |
| 291 | { | 306 | { |
| 292 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 307 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 293 | if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) | 308 | if (cpu_is_at32ap7000()) { |
| 294 | dw_dma_cyclic_free(chip->dma.rx_chan); | 309 | if (test_and_clear_bit(DMA_RX_READY, &chip->flags)) |
| 310 | dw_dma_cyclic_free(chip->dma.rx_chan); | ||
| 311 | } | ||
| 295 | return snd_pcm_lib_free_pages(substream); | 312 | return snd_pcm_lib_free_pages(substream); |
| 296 | } | 313 | } |
| 297 | 314 | ||
| @@ -299,9 +316,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) | |||
| 299 | { | 316 | { |
| 300 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 317 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 301 | struct snd_pcm_runtime *runtime = substream->runtime; | 318 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 319 | int block_size = frames_to_bytes(runtime, runtime->period_size); | ||
| 302 | unsigned long word = ac97c_readl(chip, OCA); | 320 | unsigned long word = ac97c_readl(chip, OCA); |
| 303 | int retval; | 321 | int retval; |
| 304 | 322 | ||
| 323 | chip->playback_period = 0; | ||
| 305 | word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); | 324 | word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); |
| 306 | 325 | ||
| 307 | /* assign channels to AC97C channel A */ | 326 | /* assign channels to AC97C channel A */ |
| @@ -320,11 +339,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) | |||
| 320 | ac97c_writel(chip, OCA, word); | 339 | ac97c_writel(chip, OCA, word); |
| 321 | 340 | ||
| 322 | /* configure sample format and size */ | 341 | /* configure sample format and size */ |
| 323 | word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | 342 | word = ac97c_readl(chip, CAMR); |
| 343 | if (chip->opened <= 1) | ||
| 344 | word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | ||
| 345 | else | ||
| 346 | word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | ||
| 324 | 347 | ||
| 325 | switch (runtime->format) { | 348 | switch (runtime->format) { |
| 326 | case SNDRV_PCM_FORMAT_S16_LE: | 349 | case SNDRV_PCM_FORMAT_S16_LE: |
| 327 | word |= AC97C_CMR_CEM_LITTLE; | 350 | if (cpu_is_at32ap7000()) |
| 351 | word |= AC97C_CMR_CEM_LITTLE; | ||
| 328 | break; | 352 | break; |
| 329 | case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ | 353 | case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ |
| 330 | word &= ~(AC97C_CMR_CEM_LITTLE); | 354 | word &= ~(AC97C_CMR_CEM_LITTLE); |
| @@ -363,9 +387,18 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) | |||
| 363 | dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", | 387 | dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", |
| 364 | runtime->rate); | 388 | runtime->rate); |
| 365 | 389 | ||
| 366 | if (!test_bit(DMA_TX_READY, &chip->flags)) | 390 | if (cpu_is_at32ap7000()) { |
| 367 | retval = atmel_ac97c_prepare_dma(chip, substream, | 391 | if (!test_bit(DMA_TX_READY, &chip->flags)) |
| 368 | DMA_TO_DEVICE); | 392 | retval = atmel_ac97c_prepare_dma(chip, substream, |
| 393 | DMA_TO_DEVICE); | ||
| 394 | } else { | ||
| 395 | /* Initialize and start the PDC */ | ||
| 396 | writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR); | ||
| 397 | writel(block_size / 2, chip->regs + ATMEL_PDC_TCR); | ||
| 398 | writel(runtime->dma_addr + block_size, | ||
| 399 | chip->regs + ATMEL_PDC_TNPR); | ||
| 400 | writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR); | ||
| 401 | } | ||
| 369 | 402 | ||
| 370 | return retval; | 403 | return retval; |
| 371 | } | 404 | } |
| @@ -374,9 +407,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) | |||
| 374 | { | 407 | { |
| 375 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 408 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 376 | struct snd_pcm_runtime *runtime = substream->runtime; | 409 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 410 | int block_size = frames_to_bytes(runtime, runtime->period_size); | ||
| 377 | unsigned long word = ac97c_readl(chip, ICA); | 411 | unsigned long word = ac97c_readl(chip, ICA); |
| 378 | int retval; | 412 | int retval; |
| 379 | 413 | ||
| 414 | chip->capture_period = 0; | ||
| 380 | word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); | 415 | word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT)); |
| 381 | 416 | ||
| 382 | /* assign channels to AC97C channel A */ | 417 | /* assign channels to AC97C channel A */ |
| @@ -395,11 +430,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) | |||
| 395 | ac97c_writel(chip, ICA, word); | 430 | ac97c_writel(chip, ICA, word); |
| 396 | 431 | ||
| 397 | /* configure sample format and size */ | 432 | /* configure sample format and size */ |
| 398 | word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | 433 | word = ac97c_readl(chip, CAMR); |
| 434 | if (chip->opened <= 1) | ||
| 435 | word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | ||
| 436 | else | ||
| 437 | word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16; | ||
| 399 | 438 | ||
| 400 | switch (runtime->format) { | 439 | switch (runtime->format) { |
| 401 | case SNDRV_PCM_FORMAT_S16_LE: | 440 | case SNDRV_PCM_FORMAT_S16_LE: |
| 402 | word |= AC97C_CMR_CEM_LITTLE; | 441 | if (cpu_is_at32ap7000()) |
| 442 | word |= AC97C_CMR_CEM_LITTLE; | ||
| 403 | break; | 443 | break; |
| 404 | case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ | 444 | case SNDRV_PCM_FORMAT_S16_BE: /* fall through */ |
| 405 | word &= ~(AC97C_CMR_CEM_LITTLE); | 445 | word &= ~(AC97C_CMR_CEM_LITTLE); |
| @@ -438,9 +478,18 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) | |||
| 438 | dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", | 478 | dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n", |
| 439 | runtime->rate); | 479 | runtime->rate); |
| 440 | 480 | ||
| 441 | if (!test_bit(DMA_RX_READY, &chip->flags)) | 481 | if (cpu_is_at32ap7000()) { |
| 442 | retval = atmel_ac97c_prepare_dma(chip, substream, | 482 | if (!test_bit(DMA_RX_READY, &chip->flags)) |
| 443 | DMA_FROM_DEVICE); | 483 | retval = atmel_ac97c_prepare_dma(chip, substream, |
| 484 | DMA_FROM_DEVICE); | ||
| 485 | } else { | ||
| 486 | /* Initialize and start the PDC */ | ||
| 487 | writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR); | ||
| 488 | writel(block_size / 2, chip->regs + ATMEL_PDC_RCR); | ||
| 489 | writel(runtime->dma_addr + block_size, | ||
| 490 | chip->regs + ATMEL_PDC_RNPR); | ||
| 491 | writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR); | ||
| 492 | } | ||
| 444 | 493 | ||
| 445 | return retval; | 494 | return retval; |
| 446 | } | 495 | } |
| @@ -449,7 +498,7 @@ static int | |||
| 449 | atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) | 498 | atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) |
| 450 | { | 499 | { |
| 451 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 500 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 452 | unsigned long camr; | 501 | unsigned long camr, ptcr = 0; |
| 453 | int retval = 0; | 502 | int retval = 0; |
| 454 | 503 | ||
| 455 | camr = ac97c_readl(chip, CAMR); | 504 | camr = ac97c_readl(chip, CAMR); |
| @@ -458,15 +507,22 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 458 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ | 507 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ |
| 459 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ | 508 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ |
| 460 | case SNDRV_PCM_TRIGGER_START: | 509 | case SNDRV_PCM_TRIGGER_START: |
| 461 | retval = dw_dma_cyclic_start(chip->dma.tx_chan); | 510 | if (cpu_is_at32ap7000()) { |
| 462 | if (retval) | 511 | retval = dw_dma_cyclic_start(chip->dma.tx_chan); |
| 463 | goto out; | 512 | if (retval) |
| 464 | camr |= AC97C_CMR_CENA; | 513 | goto out; |
| 514 | } else { | ||
| 515 | ptcr = ATMEL_PDC_TXTEN; | ||
| 516 | } | ||
| 517 | camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX; | ||
| 465 | break; | 518 | break; |
| 466 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ | 519 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ |
| 467 | case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ | 520 | case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ |
| 468 | case SNDRV_PCM_TRIGGER_STOP: | 521 | case SNDRV_PCM_TRIGGER_STOP: |
| 469 | dw_dma_cyclic_stop(chip->dma.tx_chan); | 522 | if (cpu_is_at32ap7000()) |
| 523 | dw_dma_cyclic_stop(chip->dma.tx_chan); | ||
| 524 | else | ||
| 525 | ptcr |= ATMEL_PDC_TXTDIS; | ||
| 470 | if (chip->opened <= 1) | 526 | if (chip->opened <= 1) |
| 471 | camr &= ~AC97C_CMR_CENA; | 527 | camr &= ~AC97C_CMR_CENA; |
| 472 | break; | 528 | break; |
| @@ -476,6 +532,8 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 476 | } | 532 | } |
| 477 | 533 | ||
| 478 | ac97c_writel(chip, CAMR, camr); | 534 | ac97c_writel(chip, CAMR, camr); |
| 535 | if (!cpu_is_at32ap7000()) | ||
| 536 | writel(ptcr, chip->regs + ATMEL_PDC_PTCR); | ||
| 479 | out: | 537 | out: |
| 480 | return retval; | 538 | return retval; |
| 481 | } | 539 | } |
| @@ -484,24 +542,32 @@ static int | |||
| 484 | atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) | 542 | atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) |
| 485 | { | 543 | { |
| 486 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); | 544 | struct atmel_ac97c *chip = snd_pcm_substream_chip(substream); |
| 487 | unsigned long camr; | 545 | unsigned long camr, ptcr = 0; |
| 488 | int retval = 0; | 546 | int retval = 0; |
| 489 | 547 | ||
| 490 | camr = ac97c_readl(chip, CAMR); | 548 | camr = ac97c_readl(chip, CAMR); |
| 549 | ptcr = readl(chip->regs + ATMEL_PDC_PTSR); | ||
| 491 | 550 | ||
| 492 | switch (cmd) { | 551 | switch (cmd) { |
| 493 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ | 552 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */ |
| 494 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ | 553 | case SNDRV_PCM_TRIGGER_RESUME: /* fall through */ |
| 495 | case SNDRV_PCM_TRIGGER_START: | 554 | case SNDRV_PCM_TRIGGER_START: |
| 496 | retval = dw_dma_cyclic_start(chip->dma.rx_chan); | 555 | if (cpu_is_at32ap7000()) { |
| 497 | if (retval) | 556 | retval = dw_dma_cyclic_start(chip->dma.rx_chan); |
| 498 | goto out; | 557 | if (retval) |
| 499 | camr |= AC97C_CMR_CENA; | 558 | goto out; |
| 559 | } else { | ||
| 560 | ptcr = ATMEL_PDC_RXTEN; | ||
| 561 | } | ||
| 562 | camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX; | ||
| 500 | break; | 563 | break; |
| 501 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ | 564 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */ |
| 502 | case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ | 565 | case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */ |
| 503 | case SNDRV_PCM_TRIGGER_STOP: | 566 | case SNDRV_PCM_TRIGGER_STOP: |
| 504 | dw_dma_cyclic_stop(chip->dma.rx_chan); | 567 | if (cpu_is_at32ap7000()) |
| 568 | dw_dma_cyclic_stop(chip->dma.rx_chan); | ||
| 569 | else | ||
| 570 | ptcr |= (ATMEL_PDC_RXTDIS); | ||
| 505 | if (chip->opened <= 1) | 571 | if (chip->opened <= 1) |
| 506 | camr &= ~AC97C_CMR_CENA; | 572 | camr &= ~AC97C_CMR_CENA; |
| 507 | break; | 573 | break; |
| @@ -511,6 +577,8 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 511 | } | 577 | } |
| 512 | 578 | ||
| 513 | ac97c_writel(chip, CAMR, camr); | 579 | ac97c_writel(chip, CAMR, camr); |
| 580 | if (!cpu_is_at32ap7000()) | ||
| 581 | writel(ptcr, chip->regs + ATMEL_PDC_PTCR); | ||
| 514 | out: | 582 | out: |
| 515 | return retval; | 583 | return retval; |
| 516 | } | 584 | } |
| @@ -523,7 +591,10 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream) | |||
| 523 | snd_pcm_uframes_t frames; | 591 | snd_pcm_uframes_t frames; |
| 524 | unsigned long bytes; | 592 | unsigned long bytes; |
| 525 | 593 | ||
| 526 | bytes = dw_dma_get_src_addr(chip->dma.tx_chan); | 594 | if (cpu_is_at32ap7000()) |
| 595 | bytes = dw_dma_get_src_addr(chip->dma.tx_chan); | ||
| 596 | else | ||
| 597 | bytes = readl(chip->regs + ATMEL_PDC_TPR); | ||
| 527 | bytes -= runtime->dma_addr; | 598 | bytes -= runtime->dma_addr; |
| 528 | 599 | ||
| 529 | frames = bytes_to_frames(runtime, bytes); | 600 | frames = bytes_to_frames(runtime, bytes); |
| @@ -540,7 +611,10 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream) | |||
| 540 | snd_pcm_uframes_t frames; | 611 | snd_pcm_uframes_t frames; |
| 541 | unsigned long bytes; | 612 | unsigned long bytes; |
| 542 | 613 | ||
| 543 | bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); | 614 | if (cpu_is_at32ap7000()) |
| 615 | bytes = dw_dma_get_dst_addr(chip->dma.rx_chan); | ||
| 616 | else | ||
| 617 | bytes = readl(chip->regs + ATMEL_PDC_RPR); | ||
| 544 | bytes -= runtime->dma_addr; | 618 | bytes -= runtime->dma_addr; |
| 545 | 619 | ||
| 546 | frames = bytes_to_frames(runtime, bytes); | 620 | frames = bytes_to_frames(runtime, bytes); |
| @@ -578,8 +652,11 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) | |||
| 578 | u32 sr = ac97c_readl(chip, SR); | 652 | u32 sr = ac97c_readl(chip, SR); |
| 579 | u32 casr = ac97c_readl(chip, CASR); | 653 | u32 casr = ac97c_readl(chip, CASR); |
| 580 | u32 cosr = ac97c_readl(chip, COSR); | 654 | u32 cosr = ac97c_readl(chip, COSR); |
| 655 | u32 camr = ac97c_readl(chip, CAMR); | ||
| 581 | 656 | ||
| 582 | if (sr & AC97C_SR_CAEVT) { | 657 | if (sr & AC97C_SR_CAEVT) { |
| 658 | struct snd_pcm_runtime *runtime; | ||
| 659 | int offset, next_period, block_size; | ||
| 583 | dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", | 660 | dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", |
| 584 | casr & AC97C_CSR_OVRUN ? " OVRUN" : "", | 661 | casr & AC97C_CSR_OVRUN ? " OVRUN" : "", |
| 585 | casr & AC97C_CSR_RXRDY ? " RXRDY" : "", | 662 | casr & AC97C_CSR_RXRDY ? " RXRDY" : "", |
| @@ -587,6 +664,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) | |||
| 587 | casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", | 664 | casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", |
| 588 | casr & AC97C_CSR_TXRDY ? " TXRDY" : "", | 665 | casr & AC97C_CSR_TXRDY ? " TXRDY" : "", |
| 589 | !casr ? " NONE" : ""); | 666 | !casr ? " NONE" : ""); |
| 667 | if (!cpu_is_at32ap7000()) { | ||
| 668 | if ((casr & camr) & AC97C_CSR_ENDTX) { | ||
| 669 | runtime = chip->playback_substream->runtime; | ||
| 670 | block_size = frames_to_bytes(runtime, | ||
| 671 | runtime->period_size); | ||
| 672 | chip->playback_period++; | ||
| 673 | |||
| 674 | if (chip->playback_period == runtime->periods) | ||
| 675 | chip->playback_period = 0; | ||
| 676 | next_period = chip->playback_period + 1; | ||
| 677 | if (next_period == runtime->periods) | ||
| 678 | next_period = 0; | ||
| 679 | |||
| 680 | offset = block_size * next_period; | ||
| 681 | |||
| 682 | writel(runtime->dma_addr + offset, | ||
| 683 | chip->regs + ATMEL_PDC_TNPR); | ||
| 684 | writel(block_size / 2, | ||
| 685 | chip->regs + ATMEL_PDC_TNCR); | ||
| 686 | |||
| 687 | snd_pcm_period_elapsed( | ||
| 688 | chip->playback_substream); | ||
| 689 | } | ||
| 690 | if ((casr & camr) & AC97C_CSR_ENDRX) { | ||
| 691 | runtime = chip->capture_substream->runtime; | ||
| 692 | block_size = frames_to_bytes(runtime, | ||
| 693 | runtime->period_size); | ||
| 694 | chip->capture_period++; | ||
| 695 | |||
| 696 | if (chip->capture_period == runtime->periods) | ||
| 697 | chip->capture_period = 0; | ||
| 698 | next_period = chip->capture_period + 1; | ||
| 699 | if (next_period == runtime->periods) | ||
| 700 | next_period = 0; | ||
| 701 | |||
| 702 | offset = block_size * next_period; | ||
| 703 | |||
| 704 | writel(runtime->dma_addr + offset, | ||
| 705 | chip->regs + ATMEL_PDC_RNPR); | ||
| 706 | writel(block_size / 2, | ||
| 707 | chip->regs + ATMEL_PDC_RNCR); | ||
| 708 | snd_pcm_period_elapsed(chip->capture_substream); | ||
| 709 | } | ||
| 710 | } | ||
| 590 | retval = IRQ_HANDLED; | 711 | retval = IRQ_HANDLED; |
| 591 | } | 712 | } |
| 592 | 713 | ||
| @@ -608,15 +729,50 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) | |||
| 608 | return retval; | 729 | return retval; |
| 609 | } | 730 | } |
| 610 | 731 | ||
| 732 | static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = { | ||
| 733 | /* Playback */ | ||
| 734 | { | ||
| 735 | .exclusive = 1, | ||
| 736 | .r = { { | ||
| 737 | .slots = ((1 << AC97_SLOT_PCM_LEFT) | ||
| 738 | | (1 << AC97_SLOT_PCM_RIGHT)), | ||
| 739 | } }, | ||
| 740 | }, | ||
| 741 | /* PCM in */ | ||
| 742 | { | ||
| 743 | .stream = 1, | ||
| 744 | .exclusive = 1, | ||
| 745 | .r = { { | ||
| 746 | .slots = ((1 << AC97_SLOT_PCM_LEFT) | ||
| 747 | | (1 << AC97_SLOT_PCM_RIGHT)), | ||
| 748 | } } | ||
| 749 | }, | ||
| 750 | /* Mic in */ | ||
| 751 | { | ||
| 752 | .stream = 1, | ||
| 753 | .exclusive = 1, | ||
| 754 | .r = { { | ||
| 755 | .slots = (1<<AC97_SLOT_MIC), | ||
| 756 | } } | ||
| 757 | }, | ||
| 758 | }; | ||
| 759 | |||
| 611 | static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) | 760 | static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) |
| 612 | { | 761 | { |
| 613 | struct snd_pcm *pcm; | 762 | struct snd_pcm *pcm; |
| 614 | struct snd_pcm_hardware hw = atmel_ac97c_hw; | 763 | struct snd_pcm_hardware hw = atmel_ac97c_hw; |
| 615 | int capture, playback, retval; | 764 | int capture, playback, retval, err; |
| 616 | 765 | ||
| 617 | capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); | 766 | capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags); |
| 618 | playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags); | 767 | playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags); |
| 619 | 768 | ||
| 769 | if (!cpu_is_at32ap7000()) { | ||
| 770 | err = snd_ac97_pcm_assign(chip->ac97_bus, | ||
| 771 | ARRAY_SIZE(at91_ac97_pcm_defs), | ||
| 772 | at91_ac97_pcm_defs); | ||
| 773 | if (err) | ||
| 774 | return err; | ||
| 775 | } | ||
| 620 | retval = snd_pcm_new(chip->card, chip->card->shortname, | 776 | retval = snd_pcm_new(chip->card, chip->card->shortname, |
| 621 | chip->pdev->id, playback, capture, &pcm); | 777 | chip->pdev->id, playback, capture, &pcm); |
| 622 | if (retval) | 778 | if (retval) |
| @@ -775,7 +931,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
| 775 | return -ENXIO; | 931 | return -ENXIO; |
| 776 | } | 932 | } |
| 777 | 933 | ||
| 778 | pclk = clk_get(&pdev->dev, "pclk"); | 934 | if (cpu_is_at32ap7000()) { |
| 935 | pclk = clk_get(&pdev->dev, "pclk"); | ||
| 936 | } else { | ||
| 937 | pclk = clk_get(&pdev->dev, "ac97_clk"); | ||
| 938 | } | ||
| 939 | |||
| 779 | if (IS_ERR(pclk)) { | 940 | if (IS_ERR(pclk)) { |
| 780 | dev_dbg(&pdev->dev, "no peripheral clock\n"); | 941 | dev_dbg(&pdev->dev, "no peripheral clock\n"); |
| 781 | return PTR_ERR(pclk); | 942 | return PTR_ERR(pclk); |
| @@ -844,43 +1005,52 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
| 844 | goto err_ac97_bus; | 1005 | goto err_ac97_bus; |
| 845 | } | 1006 | } |
| 846 | 1007 | ||
| 847 | if (pdata->rx_dws.dma_dev) { | 1008 | if (cpu_is_at32ap7000()) { |
| 848 | struct dw_dma_slave *dws = &pdata->rx_dws; | 1009 | if (pdata->rx_dws.dma_dev) { |
| 849 | dma_cap_mask_t mask; | 1010 | struct dw_dma_slave *dws = &pdata->rx_dws; |
| 1011 | dma_cap_mask_t mask; | ||
| 850 | 1012 | ||
| 851 | dws->rx_reg = regs->start + AC97C_CARHR + 2; | 1013 | dws->rx_reg = regs->start + AC97C_CARHR + 2; |
| 852 | 1014 | ||
| 853 | dma_cap_zero(mask); | 1015 | dma_cap_zero(mask); |
| 854 | dma_cap_set(DMA_SLAVE, mask); | 1016 | dma_cap_set(DMA_SLAVE, mask); |
| 855 | 1017 | ||
| 856 | chip->dma.rx_chan = dma_request_channel(mask, filter, dws); | 1018 | chip->dma.rx_chan = dma_request_channel(mask, filter, |
| 1019 | dws); | ||
| 857 | 1020 | ||
| 858 | dev_info(&chip->pdev->dev, "using %s for DMA RX\n", | 1021 | dev_info(&chip->pdev->dev, "using %s for DMA RX\n", |
| 859 | dev_name(&chip->dma.rx_chan->dev->device)); | 1022 | dev_name(&chip->dma.rx_chan->dev->device)); |
| 860 | set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); | 1023 | set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); |
| 861 | } | 1024 | } |
| 862 | 1025 | ||
| 863 | if (pdata->tx_dws.dma_dev) { | 1026 | if (pdata->tx_dws.dma_dev) { |
| 864 | struct dw_dma_slave *dws = &pdata->tx_dws; | 1027 | struct dw_dma_slave *dws = &pdata->tx_dws; |
| 865 | dma_cap_mask_t mask; | 1028 | dma_cap_mask_t mask; |
| 866 | 1029 | ||
| 867 | dws->tx_reg = regs->start + AC97C_CATHR + 2; | 1030 | dws->tx_reg = regs->start + AC97C_CATHR + 2; |
| 868 | 1031 | ||
| 869 | dma_cap_zero(mask); | 1032 | dma_cap_zero(mask); |
| 870 | dma_cap_set(DMA_SLAVE, mask); | 1033 | dma_cap_set(DMA_SLAVE, mask); |
| 871 | 1034 | ||
| 872 | chip->dma.tx_chan = dma_request_channel(mask, filter, dws); | 1035 | chip->dma.tx_chan = dma_request_channel(mask, filter, |
| 1036 | dws); | ||
| 873 | 1037 | ||
| 874 | dev_info(&chip->pdev->dev, "using %s for DMA TX\n", | 1038 | dev_info(&chip->pdev->dev, "using %s for DMA TX\n", |
| 875 | dev_name(&chip->dma.tx_chan->dev->device)); | 1039 | dev_name(&chip->dma.tx_chan->dev->device)); |
| 876 | set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); | 1040 | set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); |
| 877 | } | 1041 | } |
| 878 | 1042 | ||
| 879 | if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && | 1043 | if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) && |
| 880 | !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { | 1044 | !test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) { |
| 881 | dev_dbg(&pdev->dev, "DMA not available\n"); | 1045 | dev_dbg(&pdev->dev, "DMA not available\n"); |
| 882 | retval = -ENODEV; | 1046 | retval = -ENODEV; |
| 883 | goto err_dma; | 1047 | goto err_dma; |
| 1048 | } | ||
| 1049 | } else { | ||
| 1050 | /* Just pretend that we have DMA channel(for at91 i is actually | ||
| 1051 | * the PDC) */ | ||
| 1052 | set_bit(DMA_RX_CHAN_PRESENT, &chip->flags); | ||
| 1053 | set_bit(DMA_TX_CHAN_PRESENT, &chip->flags); | ||
| 884 | } | 1054 | } |
| 885 | 1055 | ||
| 886 | retval = atmel_ac97c_pcm_new(chip); | 1056 | retval = atmel_ac97c_pcm_new(chip); |
| @@ -897,20 +1067,22 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
| 897 | 1067 | ||
| 898 | platform_set_drvdata(pdev, card); | 1068 | platform_set_drvdata(pdev, card); |
| 899 | 1069 | ||
| 900 | dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p\n", | 1070 | dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d\n", |
| 901 | chip->regs); | 1071 | chip->regs, irq); |
| 902 | 1072 | ||
| 903 | return 0; | 1073 | return 0; |
| 904 | 1074 | ||
| 905 | err_dma: | 1075 | err_dma: |
| 906 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) | 1076 | if (cpu_is_at32ap7000()) { |
| 907 | dma_release_channel(chip->dma.rx_chan); | 1077 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) |
| 908 | if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) | 1078 | dma_release_channel(chip->dma.rx_chan); |
| 909 | dma_release_channel(chip->dma.tx_chan); | 1079 | if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) |
| 910 | clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); | 1080 | dma_release_channel(chip->dma.tx_chan); |
| 911 | clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); | 1081 | clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); |
| 912 | chip->dma.rx_chan = NULL; | 1082 | clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); |
| 913 | chip->dma.tx_chan = NULL; | 1083 | chip->dma.rx_chan = NULL; |
| 1084 | chip->dma.tx_chan = NULL; | ||
| 1085 | } | ||
| 914 | err_ac97_bus: | 1086 | err_ac97_bus: |
| 915 | snd_card_set_dev(card, NULL); | 1087 | snd_card_set_dev(card, NULL); |
| 916 | 1088 | ||
| @@ -934,10 +1106,12 @@ static int atmel_ac97c_suspend(struct platform_device *pdev, pm_message_t msg) | |||
| 934 | struct snd_card *card = platform_get_drvdata(pdev); | 1106 | struct snd_card *card = platform_get_drvdata(pdev); |
| 935 | struct atmel_ac97c *chip = card->private_data; | 1107 | struct atmel_ac97c *chip = card->private_data; |
| 936 | 1108 | ||
| 937 | if (test_bit(DMA_RX_READY, &chip->flags)) | 1109 | if (cpu_is_at32ap7000()) { |
| 938 | dw_dma_cyclic_stop(chip->dma.rx_chan); | 1110 | if (test_bit(DMA_RX_READY, &chip->flags)) |
| 939 | if (test_bit(DMA_TX_READY, &chip->flags)) | 1111 | dw_dma_cyclic_stop(chip->dma.rx_chan); |
| 940 | dw_dma_cyclic_stop(chip->dma.tx_chan); | 1112 | if (test_bit(DMA_TX_READY, &chip->flags)) |
| 1113 | dw_dma_cyclic_stop(chip->dma.tx_chan); | ||
| 1114 | } | ||
| 941 | clk_disable(chip->pclk); | 1115 | clk_disable(chip->pclk); |
| 942 | 1116 | ||
| 943 | return 0; | 1117 | return 0; |
| @@ -949,11 +1123,12 @@ static int atmel_ac97c_resume(struct platform_device *pdev) | |||
| 949 | struct atmel_ac97c *chip = card->private_data; | 1123 | struct atmel_ac97c *chip = card->private_data; |
| 950 | 1124 | ||
| 951 | clk_enable(chip->pclk); | 1125 | clk_enable(chip->pclk); |
| 952 | if (test_bit(DMA_RX_READY, &chip->flags)) | 1126 | if (cpu_is_at32ap7000()) { |
| 953 | dw_dma_cyclic_start(chip->dma.rx_chan); | 1127 | if (test_bit(DMA_RX_READY, &chip->flags)) |
| 954 | if (test_bit(DMA_TX_READY, &chip->flags)) | 1128 | dw_dma_cyclic_start(chip->dma.rx_chan); |
| 955 | dw_dma_cyclic_start(chip->dma.tx_chan); | 1129 | if (test_bit(DMA_TX_READY, &chip->flags)) |
| 956 | 1130 | dw_dma_cyclic_start(chip->dma.tx_chan); | |
| 1131 | } | ||
| 957 | return 0; | 1132 | return 0; |
| 958 | } | 1133 | } |
| 959 | #else | 1134 | #else |
| @@ -978,14 +1153,16 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) | |||
| 978 | iounmap(chip->regs); | 1153 | iounmap(chip->regs); |
| 979 | free_irq(chip->irq, chip); | 1154 | free_irq(chip->irq, chip); |
| 980 | 1155 | ||
| 981 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) | 1156 | if (cpu_is_at32ap7000()) { |
| 982 | dma_release_channel(chip->dma.rx_chan); | 1157 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) |
| 983 | if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) | 1158 | dma_release_channel(chip->dma.rx_chan); |
| 984 | dma_release_channel(chip->dma.tx_chan); | 1159 | if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) |
| 985 | clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); | 1160 | dma_release_channel(chip->dma.tx_chan); |
| 986 | clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); | 1161 | clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags); |
| 987 | chip->dma.rx_chan = NULL; | 1162 | clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags); |
| 988 | chip->dma.tx_chan = NULL; | 1163 | chip->dma.rx_chan = NULL; |
| 1164 | chip->dma.tx_chan = NULL; | ||
| 1165 | } | ||
| 989 | 1166 | ||
| 990 | snd_card_set_dev(card, NULL); | 1167 | snd_card_set_dev(card, NULL); |
| 991 | snd_card_free(card); | 1168 | snd_card_free(card); |
diff --git a/sound/core/control.c b/sound/core/control.c index 439ce64f9d82..070aab490191 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) | |||
| 50 | struct snd_ctl_file *ctl; | 50 | struct snd_ctl_file *ctl; |
| 51 | int err; | 51 | int err; |
| 52 | 52 | ||
| 53 | err = nonseekable_open(inode, file); | ||
| 54 | if (err < 0) | ||
| 55 | return err; | ||
| 56 | |||
| 53 | card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); | 57 | card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); |
| 54 | if (!card) { | 58 | if (!card) { |
| 55 | err = -ENODEV; | 59 | err = -ENODEV; |
| @@ -1388,6 +1392,7 @@ static const struct file_operations snd_ctl_f_ops = | |||
| 1388 | .read = snd_ctl_read, | 1392 | .read = snd_ctl_read, |
| 1389 | .open = snd_ctl_open, | 1393 | .open = snd_ctl_open, |
| 1390 | .release = snd_ctl_release, | 1394 | .release = snd_ctl_release, |
| 1395 | .llseek = no_llseek, | ||
| 1391 | .poll = snd_ctl_poll, | 1396 | .poll = snd_ctl_poll, |
| 1392 | .unlocked_ioctl = snd_ctl_ioctl, | 1397 | .unlocked_ioctl = snd_ctl_ioctl, |
| 1393 | .compat_ioctl = snd_ctl_ioctl_compat, | 1398 | .compat_ioctl = snd_ctl_ioctl_compat, |
diff --git a/sound/core/info.c b/sound/core/info.c index cc4a53d4b7f8..b70564ed8b37 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) | |||
| 164 | { | 164 | { |
| 165 | struct snd_info_private_data *data; | 165 | struct snd_info_private_data *data; |
| 166 | struct snd_info_entry *entry; | 166 | struct snd_info_entry *entry; |
| 167 | loff_t ret; | 167 | loff_t ret = -EINVAL, size; |
| 168 | 168 | ||
| 169 | data = file->private_data; | 169 | data = file->private_data; |
| 170 | entry = data->entry; | 170 | entry = data->entry; |
| 171 | lock_kernel(); | 171 | mutex_lock(&entry->access); |
| 172 | switch (entry->content) { | 172 | if (entry->content == SNDRV_INFO_CONTENT_DATA && |
| 173 | case SNDRV_INFO_CONTENT_TEXT: | 173 | entry->c.ops->llseek) { |
| 174 | switch (orig) { | 174 | offset = entry->c.ops->llseek(entry, |
| 175 | case SEEK_SET: | 175 | data->file_private_data, |
| 176 | file->f_pos = offset; | 176 | file, offset, orig); |
| 177 | ret = file->f_pos; | 177 | goto out; |
| 178 | goto out; | 178 | } |
| 179 | case SEEK_CUR: | 179 | if (entry->content == SNDRV_INFO_CONTENT_DATA) |
| 180 | file->f_pos += offset; | 180 | size = entry->size; |
| 181 | ret = file->f_pos; | 181 | else |
| 182 | goto out; | 182 | size = 0; |
| 183 | case SEEK_END: | 183 | switch (orig) { |
| 184 | default: | 184 | case SEEK_SET: |
| 185 | ret = -EINVAL; | ||
| 186 | goto out; | ||
| 187 | } | ||
| 188 | break; | 185 | break; |
| 189 | case SNDRV_INFO_CONTENT_DATA: | 186 | case SEEK_CUR: |
| 190 | if (entry->c.ops->llseek) { | 187 | offset += file->f_pos; |
| 191 | ret = entry->c.ops->llseek(entry, | 188 | break; |
| 192 | data->file_private_data, | 189 | case SEEK_END: |
| 193 | file, offset, orig); | 190 | if (!size) |
| 194 | goto out; | 191 | goto out; |
| 195 | } | 192 | offset += size; |
| 196 | break; | 193 | break; |
| 197 | } | 194 | default: |
| 198 | ret = -ENXIO; | 195 | goto out; |
| 199 | out: | 196 | } |
| 200 | unlock_kernel(); | 197 | if (offset < 0) |
| 198 | goto out; | ||
| 199 | if (size && offset > size) | ||
| 200 | offset = size; | ||
| 201 | file->f_pos = offset; | ||
| 202 | ret = offset; | ||
| 203 | out: | ||
| 204 | mutex_unlock(&entry->access); | ||
| 201 | return ret; | 205 | return ret; |
| 202 | } | 206 | } |
| 203 | 207 | ||
| @@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, | |||
| 232 | return -EFAULT; | 236 | return -EFAULT; |
| 233 | break; | 237 | break; |
| 234 | case SNDRV_INFO_CONTENT_DATA: | 238 | case SNDRV_INFO_CONTENT_DATA: |
| 235 | if (entry->c.ops->read) | 239 | if (pos >= entry->size) |
| 240 | return 0; | ||
| 241 | if (entry->c.ops->read) { | ||
| 242 | size = entry->size - pos; | ||
| 243 | size = min(count, size); | ||
| 236 | size = entry->c.ops->read(entry, | 244 | size = entry->c.ops->read(entry, |
| 237 | data->file_private_data, | 245 | data->file_private_data, |
| 238 | file, buffer, count, pos); | 246 | file, buffer, size, pos); |
| 247 | } | ||
| 239 | break; | 248 | break; |
| 240 | } | 249 | } |
| 241 | if ((ssize_t) size > 0) | 250 | if ((ssize_t) size > 0) |
| @@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
| 282 | size = count; | 291 | size = count; |
| 283 | break; | 292 | break; |
| 284 | case SNDRV_INFO_CONTENT_DATA: | 293 | case SNDRV_INFO_CONTENT_DATA: |
| 285 | if (entry->c.ops->write) | 294 | if (entry->c.ops->write && count > 0) { |
| 295 | size_t maxsize = entry->size - pos; | ||
| 296 | count = min(count, maxsize); | ||
| 286 | size = entry->c.ops->write(entry, | 297 | size = entry->c.ops->write(entry, |
| 287 | data->file_private_data, | 298 | data->file_private_data, |
| 288 | file, buffer, count, pos); | 299 | file, buffer, count, pos); |
| 300 | } | ||
| 289 | break; | 301 | break; |
| 290 | } | 302 | } |
| 291 | if ((ssize_t) size > 0) | 303 | if ((ssize_t) size > 0) |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 54e2eb56e4c2..f50ebf20df96 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) | |||
| 43 | struct snd_mixer_oss_file *fmixer; | 43 | struct snd_mixer_oss_file *fmixer; |
| 44 | int err; | 44 | int err; |
| 45 | 45 | ||
| 46 | err = nonseekable_open(inode, file); | ||
| 47 | if (err < 0) | ||
| 48 | return err; | ||
| 49 | |||
| 46 | card = snd_lookup_oss_minor_data(iminor(inode), | 50 | card = snd_lookup_oss_minor_data(iminor(inode), |
| 47 | SNDRV_OSS_DEVICE_TYPE_MIXER); | 51 | SNDRV_OSS_DEVICE_TYPE_MIXER); |
| 48 | if (card == NULL) | 52 | if (card == NULL) |
| @@ -397,6 +401,7 @@ static const struct file_operations snd_mixer_oss_f_ops = | |||
| 397 | .owner = THIS_MODULE, | 401 | .owner = THIS_MODULE, |
| 398 | .open = snd_mixer_oss_open, | 402 | .open = snd_mixer_oss_open, |
| 399 | .release = snd_mixer_oss_release, | 403 | .release = snd_mixer_oss_release, |
| 404 | .llseek = no_llseek, | ||
| 400 | .unlocked_ioctl = snd_mixer_oss_ioctl, | 405 | .unlocked_ioctl = snd_mixer_oss_ioctl, |
| 401 | .compat_ioctl = snd_mixer_oss_ioctl_compat, | 406 | .compat_ioctl = snd_mixer_oss_ioctl_compat, |
| 402 | }; | 407 | }; |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 82d4e3329b3d..5c8c7dff8ede 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) | |||
| 2379 | int nonblock; | 2379 | int nonblock; |
| 2380 | wait_queue_t wait; | 2380 | wait_queue_t wait; |
| 2381 | 2381 | ||
| 2382 | err = nonseekable_open(inode, file); | ||
| 2383 | if (err < 0) | ||
| 2384 | return err; | ||
| 2385 | |||
| 2382 | pcm = snd_lookup_oss_minor_data(iminor(inode), | 2386 | pcm = snd_lookup_oss_minor_data(iminor(inode), |
| 2383 | SNDRV_OSS_DEVICE_TYPE_PCM); | 2387 | SNDRV_OSS_DEVICE_TYPE_PCM); |
| 2384 | if (pcm == NULL) { | 2388 | if (pcm == NULL) { |
| @@ -2977,6 +2981,7 @@ static const struct file_operations snd_pcm_oss_f_reg = | |||
| 2977 | .write = snd_pcm_oss_write, | 2981 | .write = snd_pcm_oss_write, |
| 2978 | .open = snd_pcm_oss_open, | 2982 | .open = snd_pcm_oss_open, |
| 2979 | .release = snd_pcm_oss_release, | 2983 | .release = snd_pcm_oss_release, |
| 2984 | .llseek = no_llseek, | ||
| 2980 | .poll = snd_pcm_oss_poll, | 2985 | .poll = snd_pcm_oss_poll, |
| 2981 | .unlocked_ioctl = snd_pcm_oss_ioctl, | 2986 | .unlocked_ioctl = snd_pcm_oss_ioctl, |
| 2982 | .compat_ioctl = snd_pcm_oss_ioctl_compat, | 2987 | .compat_ioctl = snd_pcm_oss_ioctl_compat, |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 20b5982c996b..b9517f38073c 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, | |||
| 2110 | static int snd_pcm_playback_open(struct inode *inode, struct file *file) | 2110 | static int snd_pcm_playback_open(struct inode *inode, struct file *file) |
| 2111 | { | 2111 | { |
| 2112 | struct snd_pcm *pcm; | 2112 | struct snd_pcm *pcm; |
| 2113 | 2113 | int err = nonseekable_open(inode, file); | |
| 2114 | if (err < 0) | ||
| 2115 | return err; | ||
| 2114 | pcm = snd_lookup_minor_data(iminor(inode), | 2116 | pcm = snd_lookup_minor_data(iminor(inode), |
| 2115 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); | 2117 | SNDRV_DEVICE_TYPE_PCM_PLAYBACK); |
| 2116 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK); | 2118 | 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) | |||
| 2119 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) | 2121 | static int snd_pcm_capture_open(struct inode *inode, struct file *file) |
| 2120 | { | 2122 | { |
| 2121 | struct snd_pcm *pcm; | 2123 | struct snd_pcm *pcm; |
| 2122 | 2124 | int err = nonseekable_open(inode, file); | |
| 2125 | if (err < 0) | ||
| 2126 | return err; | ||
| 2123 | pcm = snd_lookup_minor_data(iminor(inode), | 2127 | pcm = snd_lookup_minor_data(iminor(inode), |
| 2124 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); | 2128 | SNDRV_DEVICE_TYPE_PCM_CAPTURE); |
| 2125 | return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE); | 2129 | 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) | |||
| 3310 | struct snd_pcm_file * pcm_file; | 3314 | struct snd_pcm_file * pcm_file; |
| 3311 | struct snd_pcm_substream *substream; | 3315 | struct snd_pcm_substream *substream; |
| 3312 | struct snd_pcm_runtime *runtime; | 3316 | struct snd_pcm_runtime *runtime; |
| 3313 | int err = -ENXIO; | ||
| 3314 | 3317 | ||
| 3315 | lock_kernel(); | ||
| 3316 | pcm_file = file->private_data; | 3318 | pcm_file = file->private_data; |
| 3317 | substream = pcm_file->substream; | 3319 | substream = pcm_file->substream; |
| 3318 | if (PCM_RUNTIME_CHECK(substream)) | 3320 | if (PCM_RUNTIME_CHECK(substream)) |
| 3319 | goto out; | 3321 | return -ENXIO; |
| 3320 | runtime = substream->runtime; | 3322 | runtime = substream->runtime; |
| 3321 | err = fasync_helper(fd, file, on, &runtime->fasync); | 3323 | return fasync_helper(fd, file, on, &runtime->fasync); |
| 3322 | out: | ||
| 3323 | unlock_kernel(); | ||
| 3324 | return err; | ||
| 3325 | } | 3324 | } |
| 3326 | 3325 | ||
| 3327 | /* | 3326 | /* |
| @@ -3462,6 +3461,7 @@ const struct file_operations snd_pcm_f_ops[2] = { | |||
| 3462 | .aio_write = snd_pcm_aio_write, | 3461 | .aio_write = snd_pcm_aio_write, |
| 3463 | .open = snd_pcm_playback_open, | 3462 | .open = snd_pcm_playback_open, |
| 3464 | .release = snd_pcm_release, | 3463 | .release = snd_pcm_release, |
| 3464 | .llseek = no_llseek, | ||
| 3465 | .poll = snd_pcm_playback_poll, | 3465 | .poll = snd_pcm_playback_poll, |
| 3466 | .unlocked_ioctl = snd_pcm_playback_ioctl, | 3466 | .unlocked_ioctl = snd_pcm_playback_ioctl, |
| 3467 | .compat_ioctl = snd_pcm_ioctl_compat, | 3467 | .compat_ioctl = snd_pcm_ioctl_compat, |
| @@ -3475,6 +3475,7 @@ const struct file_operations snd_pcm_f_ops[2] = { | |||
| 3475 | .aio_read = snd_pcm_aio_read, | 3475 | .aio_read = snd_pcm_aio_read, |
| 3476 | .open = snd_pcm_capture_open, | 3476 | .open = snd_pcm_capture_open, |
| 3477 | .release = snd_pcm_release, | 3477 | .release = snd_pcm_release, |
| 3478 | .llseek = no_llseek, | ||
| 3478 | .poll = snd_pcm_capture_poll, | 3479 | .poll = snd_pcm_capture_poll, |
| 3479 | .unlocked_ioctl = snd_pcm_capture_ioctl, | 3480 | .unlocked_ioctl = snd_pcm_capture_ioctl, |
| 3480 | .compat_ioctl = snd_pcm_ioctl_compat, | 3481 | .compat_ioctl = snd_pcm_ioctl_compat, |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 0f5a194695d9..eb68326c37d4 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) | |||
| 376 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) | 376 | if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK)) |
| 377 | return -EINVAL; /* invalid combination */ | 377 | return -EINVAL; /* invalid combination */ |
| 378 | 378 | ||
| 379 | err = nonseekable_open(inode, file); | ||
| 380 | if (err < 0) | ||
| 381 | return err; | ||
| 382 | |||
| 379 | if (maj == snd_major) { | 383 | if (maj == snd_major) { |
| 380 | rmidi = snd_lookup_minor_data(iminor(inode), | 384 | rmidi = snd_lookup_minor_data(iminor(inode), |
| 381 | SNDRV_DEVICE_TYPE_RAWMIDI); | 385 | SNDRV_DEVICE_TYPE_RAWMIDI); |
| @@ -1391,6 +1395,7 @@ static const struct file_operations snd_rawmidi_f_ops = | |||
| 1391 | .write = snd_rawmidi_write, | 1395 | .write = snd_rawmidi_write, |
| 1392 | .open = snd_rawmidi_open, | 1396 | .open = snd_rawmidi_open, |
| 1393 | .release = snd_rawmidi_release, | 1397 | .release = snd_rawmidi_release, |
| 1398 | .llseek = no_llseek, | ||
| 1394 | .poll = snd_rawmidi_poll, | 1399 | .poll = snd_rawmidi_poll, |
| 1395 | .unlocked_ioctl = snd_rawmidi_ioctl, | 1400 | .unlocked_ioctl = snd_rawmidi_ioctl, |
| 1396 | .compat_ioctl = snd_rawmidi_ioctl_compat, | 1401 | .compat_ioctl = snd_rawmidi_ioctl_compat, |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 48eca9ff9ee7..99a485f13648 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) | |||
| 318 | int c, mode; /* client id */ | 318 | int c, mode; /* client id */ |
| 319 | struct snd_seq_client *client; | 319 | struct snd_seq_client *client; |
| 320 | struct snd_seq_user_client *user; | 320 | struct snd_seq_user_client *user; |
| 321 | int err; | ||
| 322 | |||
| 323 | err = nonseekable_open(inode, file); | ||
| 324 | if (err < 0) | ||
| 325 | return err; | ||
| 321 | 326 | ||
| 322 | if (mutex_lock_interruptible(®ister_mutex)) | 327 | if (mutex_lock_interruptible(®ister_mutex)) |
| 323 | return -ERESTARTSYS; | 328 | return -ERESTARTSYS; |
| @@ -2550,6 +2555,7 @@ static const struct file_operations snd_seq_f_ops = | |||
| 2550 | .write = snd_seq_write, | 2555 | .write = snd_seq_write, |
| 2551 | .open = snd_seq_open, | 2556 | .open = snd_seq_open, |
| 2552 | .release = snd_seq_release, | 2557 | .release = snd_seq_release, |
| 2558 | .llseek = no_llseek, | ||
| 2553 | .poll = snd_seq_poll, | 2559 | .poll = snd_seq_poll, |
| 2554 | .unlocked_ioctl = snd_seq_ioctl, | 2560 | .unlocked_ioctl = snd_seq_ioctl, |
| 2555 | .compat_ioctl = snd_seq_ioctl_compat, | 2561 | .compat_ioctl = snd_seq_ioctl_compat, |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 563d1967a0ad..ac42af42b787 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) | |||
| 120 | 120 | ||
| 121 | EXPORT_SYMBOL(snd_lookup_minor_data); | 121 | EXPORT_SYMBOL(snd_lookup_minor_data); |
| 122 | 122 | ||
| 123 | static int __snd_open(struct inode *inode, struct file *file) | 123 | #ifdef CONFIG_MODULES |
| 124 | static struct snd_minor *autoload_device(unsigned int minor) | ||
| 125 | { | ||
| 126 | int dev; | ||
| 127 | mutex_unlock(&sound_mutex); /* release lock temporarily */ | ||
| 128 | dev = SNDRV_MINOR_DEVICE(minor); | ||
| 129 | if (dev == SNDRV_MINOR_CONTROL) { | ||
| 130 | /* /dev/aloadC? */ | ||
| 131 | int card = SNDRV_MINOR_CARD(minor); | ||
| 132 | if (snd_cards[card] == NULL) | ||
| 133 | snd_request_card(card); | ||
| 134 | } else if (dev == SNDRV_MINOR_GLOBAL) { | ||
| 135 | /* /dev/aloadSEQ */ | ||
| 136 | snd_request_other(minor); | ||
| 137 | } | ||
| 138 | mutex_lock(&sound_mutex); /* reacuire lock */ | ||
| 139 | return snd_minors[minor]; | ||
| 140 | } | ||
| 141 | #else /* !CONFIG_MODULES */ | ||
| 142 | #define autoload_device(minor) NULL | ||
| 143 | #endif /* CONFIG_MODULES */ | ||
| 144 | |||
| 145 | static int snd_open(struct inode *inode, struct file *file) | ||
| 124 | { | 146 | { |
| 125 | unsigned int minor = iminor(inode); | 147 | unsigned int minor = iminor(inode); |
| 126 | struct snd_minor *mptr = NULL; | 148 | struct snd_minor *mptr = NULL; |
| @@ -129,55 +151,36 @@ static int __snd_open(struct inode *inode, struct file *file) | |||
| 129 | 151 | ||
| 130 | if (minor >= ARRAY_SIZE(snd_minors)) | 152 | if (minor >= ARRAY_SIZE(snd_minors)) |
| 131 | return -ENODEV; | 153 | return -ENODEV; |
| 154 | mutex_lock(&sound_mutex); | ||
| 132 | mptr = snd_minors[minor]; | 155 | mptr = snd_minors[minor]; |
| 133 | if (mptr == NULL) { | 156 | if (mptr == NULL) { |
| 134 | #ifdef CONFIG_MODULES | 157 | mptr = autoload_device(minor); |
| 135 | int dev = SNDRV_MINOR_DEVICE(minor); | 158 | if (!mptr) { |
| 136 | if (dev == SNDRV_MINOR_CONTROL) { | 159 | mutex_unlock(&sound_mutex); |
| 137 | /* /dev/aloadC? */ | ||
| 138 | int card = SNDRV_MINOR_CARD(minor); | ||
| 139 | if (snd_cards[card] == NULL) | ||
| 140 | snd_request_card(card); | ||
| 141 | } else if (dev == SNDRV_MINOR_GLOBAL) { | ||
| 142 | /* /dev/aloadSEQ */ | ||
| 143 | snd_request_other(minor); | ||
| 144 | } | ||
| 145 | #ifndef CONFIG_SND_DYNAMIC_MINORS | ||
| 146 | /* /dev/snd/{controlC?,seq} */ | ||
| 147 | mptr = snd_minors[minor]; | ||
| 148 | if (mptr == NULL) | ||
| 149 | #endif | ||
| 150 | #endif | ||
| 151 | return -ENODEV; | 160 | return -ENODEV; |
| 161 | } | ||
| 152 | } | 162 | } |
| 153 | old_fops = file->f_op; | 163 | old_fops = file->f_op; |
| 154 | file->f_op = fops_get(mptr->f_ops); | 164 | file->f_op = fops_get(mptr->f_ops); |
| 155 | if (file->f_op == NULL) { | 165 | if (file->f_op == NULL) { |
| 156 | file->f_op = old_fops; | 166 | file->f_op = old_fops; |
| 157 | return -ENODEV; | 167 | err = -ENODEV; |
| 158 | } | 168 | } |
| 159 | if (file->f_op->open) | 169 | mutex_unlock(&sound_mutex); |
| 170 | if (err < 0) | ||
| 171 | return err; | ||
| 172 | |||
| 173 | if (file->f_op->open) { | ||
| 160 | err = file->f_op->open(inode, file); | 174 | err = file->f_op->open(inode, file); |
| 161 | if (err) { | 175 | if (err) { |
| 162 | fops_put(file->f_op); | 176 | fops_put(file->f_op); |
| 163 | file->f_op = fops_get(old_fops); | 177 | file->f_op = fops_get(old_fops); |
| 178 | } | ||
| 164 | } | 179 | } |
| 165 | fops_put(old_fops); | 180 | fops_put(old_fops); |
| 166 | return err; | 181 | return err; |
| 167 | } | 182 | } |
| 168 | 183 | ||
| 169 | |||
| 170 | /* BKL pushdown: nasty #ifdef avoidance wrapper */ | ||
| 171 | static int snd_open(struct inode *inode, struct file *file) | ||
| 172 | { | ||
| 173 | int ret; | ||
| 174 | |||
| 175 | lock_kernel(); | ||
| 176 | ret = __snd_open(inode, file); | ||
| 177 | unlock_kernel(); | ||
| 178 | return ret; | ||
| 179 | } | ||
| 180 | |||
| 181 | static const struct file_operations snd_fops = | 184 | static const struct file_operations snd_fops = |
| 182 | { | 185 | { |
| 183 | .owner = THIS_MODULE, | 186 | .owner = THIS_MODULE, |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 5040c7b862fe..13afb60999b9 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, | |||
| 1238 | static int snd_timer_user_open(struct inode *inode, struct file *file) | 1238 | static int snd_timer_user_open(struct inode *inode, struct file *file) |
| 1239 | { | 1239 | { |
| 1240 | struct snd_timer_user *tu; | 1240 | struct snd_timer_user *tu; |
| 1241 | int err; | ||
| 1242 | |||
| 1243 | err = nonseekable_open(inode, file); | ||
| 1244 | if (err < 0) | ||
| 1245 | return err; | ||
| 1241 | 1246 | ||
| 1242 | tu = kzalloc(sizeof(*tu), GFP_KERNEL); | 1247 | tu = kzalloc(sizeof(*tu), GFP_KERNEL); |
| 1243 | if (tu == NULL) | 1248 | if (tu == NULL) |
| @@ -1922,6 +1927,7 @@ static const struct file_operations snd_timer_f_ops = | |||
| 1922 | .read = snd_timer_user_read, | 1927 | .read = snd_timer_user_read, |
| 1923 | .open = snd_timer_user_open, | 1928 | .open = snd_timer_user_open, |
| 1924 | .release = snd_timer_user_release, | 1929 | .release = snd_timer_user_release, |
| 1930 | .llseek = no_llseek, | ||
| 1925 | .poll = snd_timer_user_poll, | 1931 | .poll = snd_timer_user_poll, |
| 1926 | .unlocked_ioctl = snd_timer_user_ioctl, | 1932 | .unlocked_ioctl = snd_timer_user_ioctl, |
| 1927 | .compat_ioctl = snd_timer_user_ioctl_compat, | 1933 | .compat_ioctl = snd_timer_user_ioctl_compat, |
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index 1679300b7583..df850b8830a5 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, | |||
| 49 | return 0; | 49 | return 0; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | static long snd_opl4_mem_proc_read(struct snd_info_entry *entry, void *file_private_data, | 52 | static ssize_t snd_opl4_mem_proc_read(struct snd_info_entry *entry, |
| 53 | struct file *file, char __user *_buf, | 53 | void *file_private_data, |
| 54 | unsigned long count, unsigned long pos) | 54 | struct file *file, char __user *_buf, |
| 55 | size_t count, loff_t pos) | ||
| 55 | { | 56 | { |
| 56 | struct snd_opl4 *opl4 = entry->private_data; | 57 | struct snd_opl4 *opl4 = entry->private_data; |
| 57 | long size; | ||
| 58 | char* buf; | 58 | char* buf; |
| 59 | 59 | ||
| 60 | size = count; | 60 | buf = vmalloc(count); |
| 61 | if (pos + size > entry->size) | 61 | if (!buf) |
| 62 | size = entry->size - pos; | 62 | return -ENOMEM; |
| 63 | if (size > 0) { | 63 | snd_opl4_read_memory(opl4, buf, pos, count); |
| 64 | buf = vmalloc(size); | 64 | if (copy_to_user(_buf, buf, count)) { |
| 65 | if (!buf) | ||
| 66 | return -ENOMEM; | ||
| 67 | snd_opl4_read_memory(opl4, buf, pos, size); | ||
| 68 | if (copy_to_user(_buf, buf, size)) { | ||
| 69 | vfree(buf); | ||
| 70 | return -EFAULT; | ||
| 71 | } | ||
| 72 | vfree(buf); | 65 | vfree(buf); |
| 73 | return size; | 66 | return -EFAULT; |
| 74 | } | 67 | } |
| 75 | return 0; | 68 | vfree(buf); |
| 69 | return count; | ||
| 76 | } | 70 | } |
| 77 | 71 | ||
| 78 | static long snd_opl4_mem_proc_write(struct snd_info_entry *entry, void *file_private_data, | 72 | static ssize_t snd_opl4_mem_proc_write(struct snd_info_entry *entry, |
| 79 | struct file *file, const char __user *_buf, | 73 | void *file_private_data, |
| 80 | unsigned long count, unsigned long pos) | 74 | struct file *file, |
| 75 | const char __user *_buf, | ||
| 76 | size_t count, loff_t pos) | ||
| 81 | { | 77 | { |
| 82 | struct snd_opl4 *opl4 = entry->private_data; | 78 | struct snd_opl4 *opl4 = entry->private_data; |
| 83 | long size; | ||
| 84 | char *buf; | 79 | char *buf; |
| 85 | 80 | ||
| 86 | size = count; | 81 | buf = vmalloc(count); |
| 87 | if (pos + size > entry->size) | 82 | if (!buf) |
| 88 | size = entry->size - pos; | 83 | return -ENOMEM; |
| 89 | if (size > 0) { | 84 | if (copy_from_user(buf, _buf, count)) { |
| 90 | buf = vmalloc(size); | ||
| 91 | if (!buf) | ||
| 92 | return -ENOMEM; | ||
| 93 | if (copy_from_user(buf, _buf, size)) { | ||
| 94 | vfree(buf); | ||
| 95 | return -EFAULT; | ||
| 96 | } | ||
| 97 | snd_opl4_write_memory(opl4, buf, pos, size); | ||
| 98 | vfree(buf); | 85 | vfree(buf); |
| 99 | return size; | 86 | return -EFAULT; |
| 100 | } | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | static long long snd_opl4_mem_proc_llseek(struct snd_info_entry *entry, void *file_private_data, | ||
| 105 | struct file *file, long long offset, int orig) | ||
| 106 | { | ||
| 107 | switch (orig) { | ||
| 108 | case SEEK_SET: | ||
| 109 | file->f_pos = offset; | ||
| 110 | break; | ||
| 111 | case SEEK_CUR: | ||
| 112 | file->f_pos += offset; | ||
| 113 | break; | ||
| 114 | case SEEK_END: /* offset is negative */ | ||
| 115 | file->f_pos = entry->size + offset; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | return -EINVAL; | ||
| 119 | } | 87 | } |
| 120 | if (file->f_pos > entry->size) | 88 | snd_opl4_write_memory(opl4, buf, pos, count); |
| 121 | file->f_pos = entry->size; | 89 | vfree(buf); |
| 122 | return file->f_pos; | 90 | return count; |
| 123 | } | 91 | } |
| 124 | 92 | ||
| 125 | static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { | 93 | 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 = { | |||
| 127 | .release = snd_opl4_mem_proc_release, | 95 | .release = snd_opl4_mem_proc_release, |
| 128 | .read = snd_opl4_mem_proc_read, | 96 | .read = snd_opl4_mem_proc_read, |
| 129 | .write = snd_opl4_mem_proc_write, | 97 | .write = snd_opl4_mem_proc_write, |
| 130 | .llseek = snd_opl4_mem_proc_llseek, | ||
| 131 | }; | 98 | }; |
| 132 | 99 | ||
| 133 | int snd_opl4_create_proc(struct snd_opl4 *opl4) | 100 | 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 2803e227aec9..2ccb3fadd7be 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 { | |||
| 31 | struct snd_gus_card * gus; | 31 | struct snd_gus_card * gus; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | static long snd_gf1_mem_proc_dump(struct snd_info_entry *entry, void *file_private_data, | 34 | static ssize_t snd_gf1_mem_proc_dump(struct snd_info_entry *entry, |
| 35 | struct file *file, char __user *buf, | 35 | void *file_private_data, |
| 36 | unsigned long count, unsigned long pos) | 36 | struct file *file, char __user *buf, |
| 37 | size_t count, loff_t pos) | ||
| 37 | { | 38 | { |
| 38 | long size; | ||
| 39 | struct gus_proc_private *priv = entry->private_data; | 39 | struct gus_proc_private *priv = entry->private_data; |
| 40 | struct snd_gus_card *gus = priv->gus; | 40 | struct snd_gus_card *gus = priv->gus; |
| 41 | int err; | 41 | int err; |
| 42 | 42 | ||
| 43 | size = count; | 43 | err = snd_gus_dram_read(gus, buf, pos, count, priv->rom); |
| 44 | if (pos + size > priv->size) | 44 | if (err < 0) |
| 45 | size = (long)priv->size - pos; | 45 | return err; |
| 46 | if (size > 0) { | 46 | return count; |
| 47 | if ((err = snd_gus_dram_read(gus, buf, pos, size, priv->rom)) < 0) | ||
| 48 | return err; | ||
| 49 | return size; | ||
| 50 | } | ||
| 51 | return 0; | ||
| 52 | } | 47 | } |
| 53 | 48 | ||
| 54 | static long long snd_gf1_mem_proc_llseek(struct snd_info_entry *entry, | ||
| 55 | void *private_file_data, | ||
| 56 | struct file *file, | ||
| 57 | long long offset, | ||
| 58 | int orig) | ||
| 59 | { | ||
| 60 | struct gus_proc_private *priv = entry->private_data; | ||
| 61 | |||
| 62 | switch (orig) { | ||
| 63 | case SEEK_SET: | ||
| 64 | file->f_pos = offset; | ||
| 65 | break; | ||
| 66 | case SEEK_CUR: | ||
| 67 | file->f_pos += offset; | ||
| 68 | break; | ||
| 69 | case SEEK_END: /* offset is negative */ | ||
| 70 | file->f_pos = priv->size + offset; | ||
| 71 | break; | ||
| 72 | default: | ||
| 73 | return -EINVAL; | ||
| 74 | } | ||
| 75 | if (file->f_pos > priv->size) | ||
| 76 | file->f_pos = priv->size; | ||
| 77 | return file->f_pos; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) | 49 | static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) |
| 81 | { | 50 | { |
| 82 | struct gus_proc_private *priv = entry->private_data; | 51 | struct gus_proc_private *priv = entry->private_data; |
| @@ -85,7 +54,6 @@ static void snd_gf1_mem_proc_free(struct snd_info_entry *entry) | |||
| 85 | 54 | ||
| 86 | static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { | 55 | static struct snd_info_entry_ops snd_gf1_mem_proc_ops = { |
| 87 | .read = snd_gf1_mem_proc_dump, | 56 | .read = snd_gf1_mem_proc_dump, |
| 88 | .llseek = snd_gf1_mem_proc_llseek, | ||
| 89 | }; | 57 | }; |
| 90 | 58 | ||
| 91 | int snd_gf1_mem_proc_init(struct snd_gus_card * gus) | 59 | int snd_gf1_mem_proc_init(struct snd_gus_card * gus) |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 9edc65059e3e..6772070ed492 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, | |||
| 1139 | snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); | 1139 | snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq); |
| 1140 | } | 1140 | } |
| 1141 | 1141 | ||
| 1142 | static long snd_cs4281_BA0_read(struct snd_info_entry *entry, | 1142 | static ssize_t snd_cs4281_BA0_read(struct snd_info_entry *entry, |
| 1143 | void *file_private_data, | 1143 | void *file_private_data, |
| 1144 | struct file *file, char __user *buf, | 1144 | struct file *file, char __user *buf, |
| 1145 | unsigned long count, unsigned long pos) | 1145 | size_t count, loff_t pos) |
| 1146 | { | 1146 | { |
| 1147 | long size; | ||
| 1148 | struct cs4281 *chip = entry->private_data; | 1147 | struct cs4281 *chip = entry->private_data; |
| 1149 | 1148 | ||
| 1150 | size = count; | 1149 | if (copy_to_user_fromio(buf, chip->ba0 + pos, count)) |
| 1151 | if (pos + size > CS4281_BA0_SIZE) | 1150 | return -EFAULT; |
| 1152 | size = (long)CS4281_BA0_SIZE - pos; | 1151 | return count; |
| 1153 | if (size > 0) { | ||
| 1154 | if (copy_to_user_fromio(buf, chip->ba0 + pos, size)) | ||
| 1155 | return -EFAULT; | ||
| 1156 | } | ||
| 1157 | return size; | ||
| 1158 | } | 1152 | } |
| 1159 | 1153 | ||
| 1160 | static long snd_cs4281_BA1_read(struct snd_info_entry *entry, | 1154 | static ssize_t snd_cs4281_BA1_read(struct snd_info_entry *entry, |
| 1161 | void *file_private_data, | 1155 | void *file_private_data, |
| 1162 | struct file *file, char __user *buf, | 1156 | struct file *file, char __user *buf, |
| 1163 | unsigned long count, unsigned long pos) | 1157 | size_t count, loff_t pos) |
| 1164 | { | 1158 | { |
| 1165 | long size; | ||
| 1166 | struct cs4281 *chip = entry->private_data; | 1159 | struct cs4281 *chip = entry->private_data; |
| 1167 | 1160 | ||
| 1168 | size = count; | 1161 | if (copy_to_user_fromio(buf, chip->ba1 + pos, count)) |
| 1169 | if (pos + size > CS4281_BA1_SIZE) | 1162 | return -EFAULT; |
| 1170 | size = (long)CS4281_BA1_SIZE - pos; | 1163 | return count; |
| 1171 | if (size > 0) { | ||
| 1172 | if (copy_to_user_fromio(buf, chip->ba1 + pos, size)) | ||
| 1173 | return -EFAULT; | ||
| 1174 | } | ||
| 1175 | return size; | ||
| 1176 | } | 1164 | } |
| 1177 | 1165 | ||
| 1178 | static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { | 1166 | 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 3f99a5e8528c..aad37082cb6e 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) { } | |||
| 2657 | * proc interface | 2657 | * proc interface |
| 2658 | */ | 2658 | */ |
| 2659 | 2659 | ||
| 2660 | static long snd_cs46xx_io_read(struct snd_info_entry *entry, void *file_private_data, | 2660 | static ssize_t snd_cs46xx_io_read(struct snd_info_entry *entry, |
| 2661 | struct file *file, char __user *buf, | 2661 | void *file_private_data, |
| 2662 | unsigned long count, unsigned long pos) | 2662 | struct file *file, char __user *buf, |
| 2663 | size_t count, loff_t pos) | ||
| 2663 | { | 2664 | { |
| 2664 | long size; | ||
| 2665 | struct snd_cs46xx_region *region = entry->private_data; | 2665 | struct snd_cs46xx_region *region = entry->private_data; |
| 2666 | 2666 | ||
| 2667 | size = count; | 2667 | if (copy_to_user_fromio(buf, region->remap_addr + pos, count)) |
| 2668 | if (pos + (size_t)size > region->size) | 2668 | return -EFAULT; |
| 2669 | size = region->size - pos; | 2669 | return count; |
| 2670 | if (size > 0) { | ||
| 2671 | if (copy_to_user_fromio(buf, region->remap_addr + pos, size)) | ||
| 2672 | return -EFAULT; | ||
| 2673 | } | ||
| 2674 | return size; | ||
| 2675 | } | 2670 | } |
| 2676 | 2671 | ||
| 2677 | static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { | 2672 | 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 baa7cd508cd8..bc38dd4d071f 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, | |||
| 341 | #define TOTAL_SIZE_CODE (0x200*8) | 341 | #define TOTAL_SIZE_CODE (0x200*8) |
| 342 | #define A_TOTAL_SIZE_CODE (0x400*8) | 342 | #define A_TOTAL_SIZE_CODE (0x400*8) |
| 343 | 343 | ||
| 344 | static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, | 344 | static ssize_t snd_emu10k1_fx8010_read(struct snd_info_entry *entry, |
| 345 | void *file_private_data, | 345 | void *file_private_data, |
| 346 | struct file *file, char __user *buf, | 346 | struct file *file, char __user *buf, |
| 347 | unsigned long count, unsigned long pos) | 347 | size_t count, loff_t pos) |
| 348 | { | 348 | { |
| 349 | long size; | ||
| 350 | struct snd_emu10k1 *emu = entry->private_data; | 349 | struct snd_emu10k1 *emu = entry->private_data; |
| 351 | unsigned int offset; | 350 | unsigned int offset; |
| 352 | int tram_addr = 0; | 351 | int tram_addr = 0; |
| 352 | unsigned int *tmp; | ||
| 353 | long res; | ||
| 354 | unsigned int idx; | ||
| 353 | 355 | ||
| 354 | if (!strcmp(entry->name, "fx8010_tram_addr")) { | 356 | if (!strcmp(entry->name, "fx8010_tram_addr")) { |
| 355 | offset = TANKMEMADDRREGBASE; | 357 | offset = TANKMEMADDRREGBASE; |
| @@ -361,30 +363,25 @@ static long snd_emu10k1_fx8010_read(struct snd_info_entry *entry, | |||
| 361 | } else { | 363 | } else { |
| 362 | offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; | 364 | offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; |
| 363 | } | 365 | } |
| 364 | size = count; | 366 | |
| 365 | if (pos + size > entry->size) | 367 | tmp = kmalloc(count + 8, GFP_KERNEL); |
| 366 | size = (long)entry->size - pos; | 368 | if (!tmp) |
| 367 | if (size > 0) { | 369 | return -ENOMEM; |
| 368 | unsigned int *tmp; | 370 | for (idx = 0; idx < ((pos & 3) + count + 3) >> 2; idx++) { |
| 369 | long res; | 371 | unsigned int val; |
| 370 | unsigned int idx; | 372 | val = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); |
| 371 | if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) | 373 | if (tram_addr && emu->audigy) { |
| 372 | return -ENOMEM; | 374 | val >>= 11; |
| 373 | for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) | 375 | val |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; |
| 374 | if (tram_addr && emu->audigy) { | ||
| 375 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11; | ||
| 376 | tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; | ||
| 377 | } else | ||
| 378 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); | ||
| 379 | if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size)) | ||
| 380 | res = -EFAULT; | ||
| 381 | else { | ||
| 382 | res = size; | ||
| 383 | } | 376 | } |
| 384 | kfree(tmp); | 377 | tmp[idx] = val; |
| 385 | return res; | ||
| 386 | } | 378 | } |
| 387 | return 0; | 379 | if (copy_to_user(buf, ((char *)tmp) + (pos & 3), count)) |
| 380 | res = -EFAULT; | ||
| 381 | else | ||
| 382 | res = count; | ||
| 383 | kfree(tmp); | ||
| 384 | return res; | ||
| 388 | } | 385 | } |
| 389 | 386 | ||
| 390 | static void snd_emu10k1_proc_voices_read(struct snd_info_entry *entry, | 387 | 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 9e66f6d306f8..2f6252266a02 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) | |||
| 1956 | return 0; | 1956 | return 0; |
| 1957 | } | 1957 | } |
| 1958 | 1958 | ||
| 1959 | |||
| 1960 | /* | 1959 | /* |
| 1961 | * initialize the chip | 1960 | * reset the chip |
| 1962 | */ | 1961 | */ |
| 1963 | static int __devinit aureon_init(struct snd_ice1712 *ice) | 1962 | static int aureon_reset(struct snd_ice1712 *ice) |
| 1964 | { | 1963 | { |
| 1965 | static const unsigned short wm_inits_aureon[] = { | 1964 | static const unsigned short wm_inits_aureon[] = { |
| 1966 | /* These come first to reduce init pop noise */ | 1965 | /* These come first to reduce init pop noise */ |
| @@ -2047,30 +2046,10 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
| 2047 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ | 2046 | 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ |
| 2048 | (unsigned short)-1 | 2047 | (unsigned short)-1 |
| 2049 | }; | 2048 | }; |
| 2050 | struct aureon_spec *spec; | ||
| 2051 | unsigned int tmp; | 2049 | unsigned int tmp; |
| 2052 | const unsigned short *p; | 2050 | const unsigned short *p; |
| 2053 | int err, i; | 2051 | int err; |
| 2054 | 2052 | struct aureon_spec *spec = ice->spec; | |
| 2055 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 2056 | if (!spec) | ||
| 2057 | return -ENOMEM; | ||
| 2058 | ice->spec = spec; | ||
| 2059 | |||
| 2060 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | ||
| 2061 | ice->num_total_dacs = 6; | ||
| 2062 | ice->num_total_adcs = 2; | ||
| 2063 | } else { | ||
| 2064 | /* aureon 7.1 and prodigy 7.1 */ | ||
| 2065 | ice->num_total_dacs = 8; | ||
| 2066 | ice->num_total_adcs = 2; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | /* to remeber the register values of CS8415 */ | ||
| 2070 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
| 2071 | if (!ice->akm) | ||
| 2072 | return -ENOMEM; | ||
| 2073 | ice->akm_codecs = 1; | ||
| 2074 | 2053 | ||
| 2075 | err = aureon_ac97_init(ice); | 2054 | err = aureon_ac97_init(ice); |
| 2076 | if (err != 0) | 2055 | if (err != 0) |
| @@ -2118,6 +2097,61 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
| 2118 | /* initialize PCA9554 pin directions & set default input */ | 2097 | /* initialize PCA9554 pin directions & set default input */ |
| 2119 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); | 2098 | aureon_pca9554_write(ice, PCA9554_DIR, 0x00); |
| 2120 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ | 2099 | aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ |
| 2100 | return 0; | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | /* | ||
| 2104 | * suspend/resume | ||
| 2105 | */ | ||
| 2106 | #ifdef CONFIG_PM | ||
| 2107 | static int aureon_resume(struct snd_ice1712 *ice) | ||
| 2108 | { | ||
| 2109 | struct aureon_spec *spec = ice->spec; | ||
| 2110 | int err, i; | ||
| 2111 | |||
| 2112 | err = aureon_reset(ice); | ||
| 2113 | if (err != 0) | ||
| 2114 | return err; | ||
| 2115 | |||
| 2116 | /* workaround for poking volume with alsamixer after resume: | ||
| 2117 | * just set stored volume again */ | ||
| 2118 | for (i = 0; i < ice->num_total_dacs; i++) | ||
| 2119 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); | ||
| 2120 | return 0; | ||
| 2121 | } | ||
| 2122 | #endif | ||
| 2123 | |||
| 2124 | /* | ||
| 2125 | * initialize the chip | ||
| 2126 | */ | ||
| 2127 | static int __devinit aureon_init(struct snd_ice1712 *ice) | ||
| 2128 | { | ||
| 2129 | struct aureon_spec *spec; | ||
| 2130 | int i, err; | ||
| 2131 | |||
| 2132 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 2133 | if (!spec) | ||
| 2134 | return -ENOMEM; | ||
| 2135 | ice->spec = spec; | ||
| 2136 | |||
| 2137 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { | ||
| 2138 | ice->num_total_dacs = 6; | ||
| 2139 | ice->num_total_adcs = 2; | ||
| 2140 | } else { | ||
| 2141 | /* aureon 7.1 and prodigy 7.1 */ | ||
| 2142 | ice->num_total_dacs = 8; | ||
| 2143 | ice->num_total_adcs = 2; | ||
| 2144 | } | ||
| 2145 | |||
| 2146 | /* to remeber the register values of CS8415 */ | ||
| 2147 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
| 2148 | if (!ice->akm) | ||
| 2149 | return -ENOMEM; | ||
| 2150 | ice->akm_codecs = 1; | ||
| 2151 | |||
| 2152 | err = aureon_reset(ice); | ||
| 2153 | if (err != 0) | ||
| 2154 | return err; | ||
| 2121 | 2155 | ||
| 2122 | spec->master[0] = WM_VOL_MUTE; | 2156 | spec->master[0] = WM_VOL_MUTE; |
| 2123 | spec->master[1] = WM_VOL_MUTE; | 2157 | spec->master[1] = WM_VOL_MUTE; |
| @@ -2126,6 +2160,11 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) | |||
| 2126 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); | 2160 | wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); |
| 2127 | } | 2161 | } |
| 2128 | 2162 | ||
| 2163 | #ifdef CONFIG_PM | ||
| 2164 | ice->pm_resume = aureon_resume; | ||
| 2165 | ice->pm_suspend_enabled = 1; | ||
| 2166 | #endif | ||
| 2167 | |||
| 2129 | return 0; | 2168 | return 0; |
| 2130 | } | 2169 | } |
| 2131 | 2170 | ||
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 3be8f97c8bc0..6c3fd4d1c49d 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) | |||
| 1102 | /* | 1102 | /* |
| 1103 | * proc interface | 1103 | * proc interface |
| 1104 | */ | 1104 | */ |
| 1105 | static long long snd_mixart_BA0_llseek(struct snd_info_entry *entry, | ||
| 1106 | void *private_file_data, | ||
| 1107 | struct file *file, | ||
| 1108 | long long offset, | ||
| 1109 | int orig) | ||
| 1110 | { | ||
| 1111 | offset = offset & ~3; /* 4 bytes aligned */ | ||
| 1112 | |||
| 1113 | switch(orig) { | ||
| 1114 | case SEEK_SET: | ||
| 1115 | file->f_pos = offset; | ||
| 1116 | break; | ||
| 1117 | case SEEK_CUR: | ||
| 1118 | file->f_pos += offset; | ||
| 1119 | break; | ||
| 1120 | case SEEK_END: /* offset is negative */ | ||
| 1121 | file->f_pos = MIXART_BA0_SIZE + offset; | ||
| 1122 | break; | ||
| 1123 | default: | ||
| 1124 | return -EINVAL; | ||
| 1125 | } | ||
| 1126 | if(file->f_pos > MIXART_BA0_SIZE) | ||
| 1127 | file->f_pos = MIXART_BA0_SIZE; | ||
| 1128 | return file->f_pos; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | static long long snd_mixart_BA1_llseek(struct snd_info_entry *entry, | ||
| 1132 | void *private_file_data, | ||
| 1133 | struct file *file, | ||
| 1134 | long long offset, | ||
| 1135 | int orig) | ||
| 1136 | { | ||
| 1137 | offset = offset & ~3; /* 4 bytes aligned */ | ||
| 1138 | |||
| 1139 | switch(orig) { | ||
| 1140 | case SEEK_SET: | ||
| 1141 | file->f_pos = offset; | ||
| 1142 | break; | ||
| 1143 | case SEEK_CUR: | ||
| 1144 | file->f_pos += offset; | ||
| 1145 | break; | ||
| 1146 | case SEEK_END: /* offset is negative */ | ||
| 1147 | file->f_pos = MIXART_BA1_SIZE + offset; | ||
| 1148 | break; | ||
| 1149 | default: | ||
| 1150 | return -EINVAL; | ||
| 1151 | } | ||
| 1152 | if(file->f_pos > MIXART_BA1_SIZE) | ||
| 1153 | file->f_pos = MIXART_BA1_SIZE; | ||
| 1154 | return file->f_pos; | ||
| 1155 | } | ||
| 1156 | 1105 | ||
| 1157 | /* | 1106 | /* |
| 1158 | mixart_BA0 proc interface for BAR 0 - read callback | 1107 | mixart_BA0 proc interface for BAR 0 - read callback |
| 1159 | */ | 1108 | */ |
| 1160 | static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private_data, | 1109 | static ssize_t snd_mixart_BA0_read(struct snd_info_entry *entry, |
| 1161 | struct file *file, char __user *buf, | 1110 | void *file_private_data, |
| 1162 | unsigned long count, unsigned long pos) | 1111 | struct file *file, char __user *buf, |
| 1112 | size_t count, loff_t pos) | ||
| 1163 | { | 1113 | { |
| 1164 | struct mixart_mgr *mgr = entry->private_data; | 1114 | struct mixart_mgr *mgr = entry->private_data; |
| 1165 | unsigned long maxsize; | ||
| 1166 | 1115 | ||
| 1167 | if (pos >= MIXART_BA0_SIZE) | ||
| 1168 | return 0; | ||
| 1169 | maxsize = MIXART_BA0_SIZE - pos; | ||
| 1170 | if (count > maxsize) | ||
| 1171 | count = maxsize; | ||
| 1172 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ | 1116 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ |
| 1173 | if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) | 1117 | if (copy_to_user_fromio(buf, MIXART_MEM(mgr, pos), count)) |
| 1174 | return -EFAULT; | 1118 | return -EFAULT; |
| @@ -1178,18 +1122,13 @@ static long snd_mixart_BA0_read(struct snd_info_entry *entry, void *file_private | |||
| 1178 | /* | 1122 | /* |
| 1179 | mixart_BA1 proc interface for BAR 1 - read callback | 1123 | mixart_BA1 proc interface for BAR 1 - read callback |
| 1180 | */ | 1124 | */ |
| 1181 | static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private_data, | 1125 | static ssize_t snd_mixart_BA1_read(struct snd_info_entry *entry, |
| 1182 | struct file *file, char __user *buf, | 1126 | void *file_private_data, |
| 1183 | unsigned long count, unsigned long pos) | 1127 | struct file *file, char __user *buf, |
| 1128 | size_t count, loff_t pos) | ||
| 1184 | { | 1129 | { |
| 1185 | struct mixart_mgr *mgr = entry->private_data; | 1130 | struct mixart_mgr *mgr = entry->private_data; |
| 1186 | unsigned long maxsize; | ||
| 1187 | 1131 | ||
| 1188 | if (pos > MIXART_BA1_SIZE) | ||
| 1189 | return 0; | ||
| 1190 | maxsize = MIXART_BA1_SIZE - pos; | ||
| 1191 | if (count > maxsize) | ||
| 1192 | count = maxsize; | ||
| 1193 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ | 1132 | count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ |
| 1194 | if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) | 1133 | if (copy_to_user_fromio(buf, MIXART_REG(mgr, pos), count)) |
| 1195 | return -EFAULT; | 1134 | return -EFAULT; |
| @@ -1198,12 +1137,10 @@ static long snd_mixart_BA1_read(struct snd_info_entry *entry, void *file_private | |||
| 1198 | 1137 | ||
| 1199 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { | 1138 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { |
| 1200 | .read = snd_mixart_BA0_read, | 1139 | .read = snd_mixart_BA0_read, |
| 1201 | .llseek = snd_mixart_BA0_llseek | ||
| 1202 | }; | 1140 | }; |
| 1203 | 1141 | ||
| 1204 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { | 1142 | static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { |
| 1205 | .read = snd_mixart_BA1_read, | 1143 | .read = snd_mixart_BA1_read, |
| 1206 | .llseek = snd_mixart_BA1_llseek | ||
| 1207 | }; | 1144 | }; |
| 1208 | 1145 | ||
| 1209 | 1146 | ||
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 789f44f4ac78..20afdf9772ee 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/kmod.h> | 30 | #include <linux/kmod.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
| 33 | #include <linux/string.h> | ||
| 33 | #include <sound/core.h> | 34 | #include <sound/core.h> |
| 34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
| 35 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
| @@ -46,6 +47,8 @@ | |||
| 46 | #define DBG(fmt...) | 47 | #define DBG(fmt...) |
| 47 | #endif | 48 | #endif |
| 48 | 49 | ||
| 50 | #define IS_G4DA (of_machine_is_compatible("PowerMac3,4")) | ||
| 51 | |||
| 49 | /* i2c address for tumbler */ | 52 | /* i2c address for tumbler */ |
| 50 | #define TAS_I2C_ADDR 0x34 | 53 | #define TAS_I2C_ADDR 0x34 |
| 51 | 54 | ||
| @@ -243,6 +246,7 @@ static int tumbler_set_master_volume(struct pmac_tumbler *mix) | |||
| 243 | snd_printk(KERN_ERR "failed to set volume \n"); | 246 | snd_printk(KERN_ERR "failed to set volume \n"); |
| 244 | return -EINVAL; | 247 | return -EINVAL; |
| 245 | } | 248 | } |
| 249 | DBG("(I) succeeded to set volume (%u, %u)\n", left_vol, right_vol); | ||
| 246 | return 0; | 250 | return 0; |
| 247 | } | 251 | } |
| 248 | 252 | ||
| @@ -353,6 +357,7 @@ static int tumbler_set_drc(struct pmac_tumbler *mix) | |||
| 353 | snd_printk(KERN_ERR "failed to set DRC\n"); | 357 | snd_printk(KERN_ERR "failed to set DRC\n"); |
| 354 | return -EINVAL; | 358 | return -EINVAL; |
| 355 | } | 359 | } |
| 360 | DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]); | ||
| 356 | return 0; | 361 | return 0; |
| 357 | } | 362 | } |
| 358 | 363 | ||
| @@ -389,6 +394,7 @@ static int snapper_set_drc(struct pmac_tumbler *mix) | |||
| 389 | snd_printk(KERN_ERR "failed to set DRC\n"); | 394 | snd_printk(KERN_ERR "failed to set DRC\n"); |
| 390 | return -EINVAL; | 395 | return -EINVAL; |
| 391 | } | 396 | } |
| 397 | DBG("(I) succeeded to set DRC (%u, %u)\n", val[0], val[1]); | ||
| 392 | return 0; | 398 | return 0; |
| 393 | } | 399 | } |
| 394 | 400 | ||
| @@ -1134,7 +1140,8 @@ static long tumbler_find_device(const char *device, const char *platform, | |||
| 1134 | gp->inactive_val = (*base) ? 0x4 : 0x5; | 1140 | gp->inactive_val = (*base) ? 0x4 : 0x5; |
| 1135 | } else { | 1141 | } else { |
| 1136 | const u32 *prop = NULL; | 1142 | const u32 *prop = NULL; |
| 1137 | gp->active_state = 0; | 1143 | gp->active_state = IS_G4DA |
| 1144 | && !strncmp(device, "keywest-gpio1", 13); | ||
| 1138 | gp->active_val = 0x4; | 1145 | gp->active_val = 0x4; |
| 1139 | gp->inactive_val = 0x5; | 1146 | gp->inactive_val = 0x5; |
| 1140 | /* Here are some crude hacks to extract the GPIO polarity and | 1147 | /* Here are some crude hacks to extract the GPIO polarity and |
| @@ -1312,6 +1319,9 @@ static int __devinit tumbler_init(struct snd_pmac *chip) | |||
| 1312 | if (irq <= NO_IRQ) | 1319 | if (irq <= NO_IRQ) |
| 1313 | irq = tumbler_find_device("line-output-detect", | 1320 | irq = tumbler_find_device("line-output-detect", |
| 1314 | NULL, &mix->line_detect, 1); | 1321 | NULL, &mix->line_detect, 1); |
| 1322 | if (IS_G4DA && irq <= NO_IRQ) | ||
| 1323 | irq = tumbler_find_device("keywest-gpio16", | ||
| 1324 | NULL, &mix->line_detect, 1); | ||
| 1315 | mix->lineout_irq = irq; | 1325 | mix->lineout_irq = irq; |
| 1316 | 1326 | ||
| 1317 | tumbler_reset_audio(chip); | 1327 | tumbler_reset_audio(chip); |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index c570ae3e6d55..c4dcbadd83aa 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
| @@ -65,6 +65,7 @@ config SND_USB_CAIAQ | |||
| 65 | * Native Instruments Audio 8 DJ | 65 | * Native Instruments Audio 8 DJ |
| 66 | * Native Instruments Guitar Rig Session I/O | 66 | * Native Instruments Guitar Rig Session I/O |
| 67 | * Native Instruments Guitar Rig mobile | 67 | * Native Instruments Guitar Rig mobile |
| 68 | * Native Instruments Traktor Kontrol X1 | ||
| 68 | 69 | ||
| 69 | To compile this driver as a module, choose M here: the module | 70 | To compile this driver as a module, choose M here: the module |
| 70 | will be called snd-usb-caiaq. | 71 | will be called snd-usb-caiaq. |
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index 537102ba6b9d..36ed703a7416 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, | |||
| 35 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | 35 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); |
| 36 | int pos = kcontrol->private_value; | 36 | int pos = kcontrol->private_value; |
| 37 | int is_intval = pos & CNT_INTVAL; | 37 | int is_intval = pos & CNT_INTVAL; |
| 38 | unsigned int id = dev->chip.usb_id; | 38 | int maxval = 63; |
| 39 | 39 | ||
| 40 | uinfo->count = 1; | 40 | uinfo->count = 1; |
| 41 | pos &= ~CNT_INTVAL; | 41 | pos &= ~CNT_INTVAL; |
| 42 | 42 | ||
| 43 | if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) | 43 | switch (dev->chip.usb_id) { |
| 44 | && (pos == 0)) { | 44 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): |
| 45 | /* current input mode of A8DJ */ | 45 | if (pos == 0) { |
| 46 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 46 | /* current input mode of A8DJ */ |
| 47 | uinfo->value.integer.min = 0; | 47 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 48 | uinfo->value.integer.max = 2; | 48 | uinfo->value.integer.min = 0; |
| 49 | return 0; | 49 | uinfo->value.integer.max = 2; |
| 50 | } | 50 | return 0; |
| 51 | } | ||
| 52 | break; | ||
| 51 | 53 | ||
| 52 | if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ) | 54 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): |
| 53 | && (pos == 0)) { | 55 | if (pos == 0) { |
| 54 | /* current input mode of A4DJ */ | 56 | /* current input mode of A4DJ */ |
| 55 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 57 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 56 | uinfo->value.integer.min = 0; | 58 | uinfo->value.integer.min = 0; |
| 57 | uinfo->value.integer.max = 1; | 59 | uinfo->value.integer.max = 1; |
| 58 | return 0; | 60 | return 0; |
| 61 | } | ||
| 62 | break; | ||
| 63 | |||
| 64 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 65 | maxval = 127; | ||
| 66 | break; | ||
| 59 | } | 67 | } |
| 60 | 68 | ||
| 61 | if (is_intval) { | 69 | if (is_intval) { |
| 62 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 70 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
| 63 | uinfo->value.integer.min = 0; | 71 | uinfo->value.integer.min = 0; |
| 64 | uinfo->value.integer.max = 64; | 72 | uinfo->value.integer.max = maxval; |
| 65 | } else { | 73 | } else { |
| 66 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 74 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
| 67 | uinfo->value.integer.min = 0; | 75 | uinfo->value.integer.min = 0; |
| @@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
| 102 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); | 110 | struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); |
| 103 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); | 111 | struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); |
| 104 | int pos = kcontrol->private_value; | 112 | int pos = kcontrol->private_value; |
| 113 | unsigned char cmd = EP1_CMD_WRITE_IO; | ||
| 105 | 114 | ||
| 106 | if (dev->chip.usb_id == | 115 | switch (dev->chip.usb_id) { |
| 107 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { | 116 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): { |
| 108 | /* A4DJ has only one control */ | 117 | /* A4DJ has only one control */ |
| 109 | /* do not expose hardware input mode 0 */ | 118 | /* do not expose hardware input mode 0 */ |
| 110 | dev->control_state[0] = ucontrol->value.integer.value[0] + 1; | 119 | dev->control_state[0] = ucontrol->value.integer.value[0] + 1; |
| @@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
| 113 | return 1; | 122 | return 1; |
| 114 | } | 123 | } |
| 115 | 124 | ||
| 125 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 126 | cmd = EP1_CMD_DIMM_LEDS; | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | |||
| 116 | if (pos & CNT_INTVAL) { | 130 | if (pos & CNT_INTVAL) { |
| 117 | dev->control_state[pos & ~CNT_INTVAL] | 131 | dev->control_state[pos & ~CNT_INTVAL] |
| 118 | = ucontrol->value.integer.value[0]; | 132 | = ucontrol->value.integer.value[0]; |
| 119 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, | 133 | snd_usb_caiaq_send_command(dev, cmd, |
| 120 | dev->control_state, sizeof(dev->control_state)); | 134 | dev->control_state, sizeof(dev->control_state)); |
| 121 | } else { | 135 | } else { |
| 122 | if (ucontrol->value.integer.value[0]) | 136 | if (ucontrol->value.integer.value[0]) |
| @@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
| 124 | else | 138 | else |
| 125 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); | 139 | dev->control_state[pos / 8] &= ~(1 << (pos % 8)); |
| 126 | 140 | ||
| 127 | snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, | 141 | snd_usb_caiaq_send_command(dev, cmd, |
| 128 | dev->control_state, sizeof(dev->control_state)); | 142 | dev->control_state, sizeof(dev->control_state)); |
| 129 | } | 143 | } |
| 130 | 144 | ||
| @@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = { | |||
| 273 | { "Current input mode", 0 | CNT_INTVAL } | 287 | { "Current input mode", 0 | CNT_INTVAL } |
| 274 | }; | 288 | }; |
| 275 | 289 | ||
| 290 | static struct caiaq_controller kontrolx1_controller[] = { | ||
| 291 | { "LED FX A: ON", 7 | CNT_INTVAL }, | ||
| 292 | { "LED FX A: 1", 6 | CNT_INTVAL }, | ||
| 293 | { "LED FX A: 2", 5 | CNT_INTVAL }, | ||
| 294 | { "LED FX A: 3", 4 | CNT_INTVAL }, | ||
| 295 | { "LED FX B: ON", 3 | CNT_INTVAL }, | ||
| 296 | { "LED FX B: 1", 2 | CNT_INTVAL }, | ||
| 297 | { "LED FX B: 2", 1 | CNT_INTVAL }, | ||
| 298 | { "LED FX B: 3", 0 | CNT_INTVAL }, | ||
| 299 | |||
| 300 | { "LED Hotcue", 28 | CNT_INTVAL }, | ||
| 301 | { "LED Shift (white)", 29 | CNT_INTVAL }, | ||
| 302 | { "LED Shift (green)", 30 | CNT_INTVAL }, | ||
| 303 | |||
| 304 | { "LED Deck A: FX1", 24 | CNT_INTVAL }, | ||
| 305 | { "LED Deck A: FX2", 25 | CNT_INTVAL }, | ||
| 306 | { "LED Deck A: IN", 17 | CNT_INTVAL }, | ||
| 307 | { "LED Deck A: OUT", 16 | CNT_INTVAL }, | ||
| 308 | { "LED Deck A: < BEAT", 19 | CNT_INTVAL }, | ||
| 309 | { "LED Deck A: BEAT >", 18 | CNT_INTVAL }, | ||
| 310 | { "LED Deck A: CUE/ABS", 21 | CNT_INTVAL }, | ||
| 311 | { "LED Deck A: CUP/REL", 20 | CNT_INTVAL }, | ||
| 312 | { "LED Deck A: PLAY", 23 | CNT_INTVAL }, | ||
| 313 | { "LED Deck A: SYNC", 22 | CNT_INTVAL }, | ||
| 314 | |||
| 315 | { "LED Deck B: FX1", 26 | CNT_INTVAL }, | ||
| 316 | { "LED Deck B: FX2", 27 | CNT_INTVAL }, | ||
| 317 | { "LED Deck B: IN", 15 | CNT_INTVAL }, | ||
| 318 | { "LED Deck B: OUT", 14 | CNT_INTVAL }, | ||
| 319 | { "LED Deck B: < BEAT", 13 | CNT_INTVAL }, | ||
| 320 | { "LED Deck B: BEAT >", 12 | CNT_INTVAL }, | ||
| 321 | { "LED Deck B: CUE/ABS", 11 | CNT_INTVAL }, | ||
| 322 | { "LED Deck B: CUP/REL", 10 | CNT_INTVAL }, | ||
| 323 | { "LED Deck B: PLAY", 9 | CNT_INTVAL }, | ||
| 324 | { "LED Deck B: SYNC", 8 | CNT_INTVAL }, | ||
| 325 | }; | ||
| 326 | |||
| 276 | static int __devinit add_controls(struct caiaq_controller *c, int num, | 327 | static int __devinit add_controls(struct caiaq_controller *c, int num, |
| 277 | struct snd_usb_caiaqdev *dev) | 328 | struct snd_usb_caiaqdev *dev) |
| 278 | { | 329 | { |
| @@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) | |||
| 321 | ret = add_controls(a8dj_controller, | 372 | ret = add_controls(a8dj_controller, |
| 322 | ARRAY_SIZE(a8dj_controller), dev); | 373 | ARRAY_SIZE(a8dj_controller), dev); |
| 323 | break; | 374 | break; |
| 375 | |||
| 324 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): | 376 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): |
| 325 | ret = add_controls(a4dj_controller, | 377 | ret = add_controls(a4dj_controller, |
| 326 | ARRAY_SIZE(a4dj_controller), dev); | 378 | ARRAY_SIZE(a4dj_controller), dev); |
| 327 | break; | 379 | break; |
| 380 | |||
| 381 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 382 | ret = add_controls(kontrolx1_controller, | ||
| 383 | ARRAY_SIZE(kontrolx1_controller), dev); | ||
| 384 | break; | ||
| 328 | } | 385 | } |
| 329 | 386 | ||
| 330 | return ret; | 387 | return ret; |
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index afc5aeb68005..805271827675 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c | |||
| @@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | |||
| 47 | "{Native Instruments, Audio 4 DJ}," | 47 | "{Native Instruments, Audio 4 DJ}," |
| 48 | "{Native Instruments, Audio 8 DJ}," | 48 | "{Native Instruments, Audio 8 DJ}," |
| 49 | "{Native Instruments, Session I/O}," | 49 | "{Native Instruments, Session I/O}," |
| 50 | "{Native Instruments, GuitarRig mobile}"); | 50 | "{Native Instruments, GuitarRig mobile}" |
| 51 | "{Native Instruments, Traktor Kontrol X1}"); | ||
| 51 | 52 | ||
| 52 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | 53 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ |
| 53 | static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | 54 | 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[] = { | |||
| 128 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | 129 | .idVendor = USB_VID_NATIVEINSTRUMENTS, |
| 129 | .idProduct = USB_PID_AUDIO2DJ | 130 | .idProduct = USB_PID_AUDIO2DJ |
| 130 | }, | 131 | }, |
| 132 | { | ||
| 133 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | ||
| 134 | .idVendor = USB_VID_NATIVEINSTRUMENTS, | ||
| 135 | .idProduct = USB_PID_TRAKTORKONTROLX1 | ||
| 136 | }, | ||
| 131 | { /* terminator */ } | 137 | { /* terminator */ } |
| 132 | }; | 138 | }; |
| 133 | 139 | ||
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h index 44e3edf88bef..f1117ecc84fd 100644 --- a/sound/usb/caiaq/device.h +++ b/sound/usb/caiaq/device.h | |||
| @@ -5,18 +5,20 @@ | |||
| 5 | 5 | ||
| 6 | #define USB_VID_NATIVEINSTRUMENTS 0x17cc | 6 | #define USB_VID_NATIVEINSTRUMENTS 0x17cc |
| 7 | 7 | ||
| 8 | #define USB_PID_RIGKONTROL2 0x1969 | 8 | #define USB_PID_RIGKONTROL2 0x1969 |
| 9 | #define USB_PID_RIGKONTROL3 0x1940 | 9 | #define USB_PID_RIGKONTROL3 0x1940 |
| 10 | #define USB_PID_KORECONTROLLER 0x4711 | 10 | #define USB_PID_KORECONTROLLER 0x4711 |
| 11 | #define USB_PID_KORECONTROLLER2 0x4712 | 11 | #define USB_PID_KORECONTROLLER2 0x4712 |
| 12 | #define USB_PID_AK1 0x0815 | 12 | #define USB_PID_AK1 0x0815 |
| 13 | #define USB_PID_AUDIO2DJ 0x041c | 13 | #define USB_PID_AUDIO2DJ 0x041c |
| 14 | #define USB_PID_AUDIO4DJ 0x0839 | 14 | #define USB_PID_AUDIO4DJ 0x0839 |
| 15 | #define USB_PID_AUDIO8DJ 0x1978 | 15 | #define USB_PID_AUDIO8DJ 0x1978 |
| 16 | #define USB_PID_SESSIONIO 0x1915 | 16 | #define USB_PID_SESSIONIO 0x1915 |
| 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d | 17 | #define USB_PID_GUITARRIGMOBILE 0x0d8d |
| 18 | #define USB_PID_TRAKTORKONTROLX1 0x2305 | ||
| 18 | 19 | ||
| 19 | #define EP1_BUFSIZE 64 | 20 | #define EP1_BUFSIZE 64 |
| 21 | #define EP4_BUFSIZE 512 | ||
| 20 | #define CAIAQ_USB_STR_LEN 0xff | 22 | #define CAIAQ_USB_STR_LEN 0xff |
| 21 | #define MAX_STREAMS 32 | 23 | #define MAX_STREAMS 32 |
| 22 | 24 | ||
| @@ -104,6 +106,8 @@ struct snd_usb_caiaqdev { | |||
| 104 | struct input_dev *input_dev; | 106 | struct input_dev *input_dev; |
| 105 | char phys[64]; /* physical device path */ | 107 | char phys[64]; /* physical device path */ |
| 106 | unsigned short keycode[64]; | 108 | unsigned short keycode[64]; |
| 109 | struct urb *ep4_in_urb; | ||
| 110 | unsigned char ep4_in_buf[EP4_BUFSIZE]; | ||
| 107 | #endif | 111 | #endif |
| 108 | 112 | ||
| 109 | /* ALSA */ | 113 | /* ALSA */ |
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c index a48d309bd94c..27ed0bc651ae 100644 --- a/sound/usb/caiaq/input.c +++ b/sound/usb/caiaq/input.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/usb.h> | 20 | #include <linux/usb.h> |
| 21 | #include <linux/usb/input.h> | 21 | #include <linux/usb/input.h> |
| 22 | #include <sound/core.h> | ||
| 22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
| 23 | 24 | ||
| 24 | #include "device.h" | 25 | #include "device.h" |
| @@ -65,6 +66,8 @@ static unsigned short keycode_kore[] = { | |||
| 65 | KEY_BRL_DOT5 | 66 | KEY_BRL_DOT5 |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 69 | #define KONTROLX1_INPUTS 40 | ||
| 70 | |||
| 68 | #define DEG90 (range / 2) | 71 | #define DEG90 (range / 2) |
| 69 | #define DEG180 (range) | 72 | #define DEG180 (range) |
| 70 | #define DEG270 (DEG90 + DEG180) | 73 | #define DEG270 (DEG90 + DEG180) |
| @@ -162,6 +165,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | |||
| 162 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); | 165 | input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); |
| 163 | input_sync(input_dev); | 166 | input_sync(input_dev); |
| 164 | break; | 167 | break; |
| 168 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 169 | input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]); | ||
| 170 | input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]); | ||
| 171 | input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]); | ||
| 172 | input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]); | ||
| 173 | input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]); | ||
| 174 | input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]); | ||
| 175 | input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]); | ||
| 176 | input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]); | ||
| 177 | input_sync(input_dev); | ||
| 178 | break; | ||
| 165 | } | 179 | } |
| 166 | } | 180 | } |
| 167 | 181 | ||
| @@ -201,7 +215,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | |||
| 201 | } | 215 | } |
| 202 | 216 | ||
| 203 | static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | 217 | static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, |
| 204 | char *buf, unsigned int len) | 218 | unsigned char *buf, unsigned int len) |
| 205 | { | 219 | { |
| 206 | struct input_dev *input_dev = dev->input_dev; | 220 | struct input_dev *input_dev = dev->input_dev; |
| 207 | unsigned short *keycode = input_dev->keycode; | 221 | unsigned short *keycode = input_dev->keycode; |
| @@ -218,15 +232,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | |||
| 218 | input_report_key(input_dev, keycode[i], | 232 | input_report_key(input_dev, keycode[i], |
| 219 | buf[i / 8] & (1 << (i % 8))); | 233 | buf[i / 8] & (1 << (i % 8))); |
| 220 | 234 | ||
| 221 | if (dev->chip.usb_id == | 235 | switch (dev->chip.usb_id) { |
| 222 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || | 236 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): |
| 223 | dev->chip.usb_id == | 237 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): |
| 224 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2)) | ||
| 225 | input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); | 238 | input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); |
| 239 | break; | ||
| 240 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 241 | /* rotary encoders */ | ||
| 242 | input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf); | ||
| 243 | input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4); | ||
| 244 | input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf); | ||
| 245 | input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4); | ||
| 246 | break; | ||
| 247 | } | ||
| 226 | 248 | ||
| 227 | input_sync(input_dev); | 249 | input_sync(input_dev); |
| 228 | } | 250 | } |
| 229 | 251 | ||
| 252 | static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb) | ||
| 253 | { | ||
| 254 | struct snd_usb_caiaqdev *dev = urb->context; | ||
| 255 | unsigned char *buf = urb->transfer_buffer; | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | if (urb->status || !dev || urb != dev->ep4_in_urb) | ||
| 259 | return; | ||
| 260 | |||
| 261 | if (urb->actual_length < 24) | ||
| 262 | goto requeue; | ||
| 263 | |||
| 264 | switch (dev->chip.usb_id) { | ||
| 265 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 266 | if (buf[0] & 0x3) | ||
| 267 | snd_caiaq_input_read_io(dev, buf + 1, 7); | ||
| 268 | |||
| 269 | if (buf[0] & 0x4) | ||
| 270 | snd_caiaq_input_read_analog(dev, buf + 8, 16); | ||
| 271 | |||
| 272 | break; | ||
| 273 | } | ||
| 274 | |||
| 275 | requeue: | ||
| 276 | dev->ep4_in_urb->actual_length = 0; | ||
| 277 | ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC); | ||
| 278 | if (ret < 0) | ||
| 279 | log("unable to submit urb. OOM!?\n"); | ||
| 280 | } | ||
| 281 | |||
| 282 | static int snd_usb_caiaq_input_open(struct input_dev *idev) | ||
| 283 | { | ||
| 284 | struct snd_usb_caiaqdev *dev = input_get_drvdata(idev); | ||
| 285 | |||
| 286 | if (!dev) | ||
| 287 | return -EINVAL; | ||
| 288 | |||
| 289 | switch (dev->chip.usb_id) { | ||
| 290 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 291 | if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0) | ||
| 292 | return -EIO; | ||
| 293 | break; | ||
| 294 | } | ||
| 295 | |||
| 296 | return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | static void snd_usb_caiaq_input_close(struct input_dev *idev) | ||
| 300 | { | ||
| 301 | struct snd_usb_caiaqdev *dev = input_get_drvdata(idev); | ||
| 302 | |||
| 303 | if (!dev) | ||
| 304 | return; | ||
| 305 | |||
| 306 | switch (dev->chip.usb_id) { | ||
| 307 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 308 | usb_kill_urb(dev->ep4_in_urb); | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 230 | void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, | 313 | void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, |
| 231 | char *buf, | 314 | char *buf, |
| 232 | unsigned int len) | 315 | unsigned int len) |
| @@ -251,7 +334,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
| 251 | { | 334 | { |
| 252 | struct usb_device *usb_dev = dev->chip.dev; | 335 | struct usb_device *usb_dev = dev->chip.dev; |
| 253 | struct input_dev *input; | 336 | struct input_dev *input; |
| 254 | int i, ret; | 337 | int i, ret = 0; |
| 255 | 338 | ||
| 256 | input = input_allocate_device(); | 339 | input = input_allocate_device(); |
| 257 | if (!input) | 340 | if (!input) |
| @@ -265,7 +348,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |||
| 265 | usb_to_input_id(usb_dev, &input->id); | 348 | usb_to_input_id(usb_dev, &input->id); |
| 266 | input->dev.parent = &usb_dev->dev; | 349 | input->dev.parent = &usb_dev->dev; |
| 267 | 350 | ||
| 268 | switch (dev->chip.usb_id) { | 351 | input_set_drvdata(input, dev); |
| 352 | |||
| 353 | switch (dev->chip.usb_id) { | ||
| 269 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | 354 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): |
| 270 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 355 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
| 271 | input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | 356 | 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) | |||
| 326 | input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); | 411 | input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); |
| 327 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | 412 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); |
| 328 | break; | 413 | break; |
| 414 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): | ||
| 415 | input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
| 416 | input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | | ||
| 417 | BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) | | ||
| 418 | BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) | | ||
| 419 | BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) | | ||
| 420 | BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | ||
| 421 | BIT_MASK(ABS_Z); | ||
| 422 | input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC); | ||
| 423 | BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS); | ||
| 424 | for (i = 0; i < KONTROLX1_INPUTS; i++) | ||
| 425 | dev->keycode[i] = BTN_MISC + i; | ||
| 426 | input->keycodemax = KONTROLX1_INPUTS; | ||
| 427 | |||
| 428 | /* analog potentiometers */ | ||
| 429 | input_set_abs_params(input, ABS_HAT0X, 0, 4096, 0, 10); | ||
| 430 | input_set_abs_params(input, ABS_HAT0Y, 0, 4096, 0, 10); | ||
| 431 | input_set_abs_params(input, ABS_HAT1X, 0, 4096, 0, 10); | ||
| 432 | input_set_abs_params(input, ABS_HAT1Y, 0, 4096, 0, 10); | ||
| 433 | input_set_abs_params(input, ABS_HAT2X, 0, 4096, 0, 10); | ||
| 434 | input_set_abs_params(input, ABS_HAT2Y, 0, 4096, 0, 10); | ||
| 435 | input_set_abs_params(input, ABS_HAT3X, 0, 4096, 0, 10); | ||
| 436 | input_set_abs_params(input, ABS_HAT3Y, 0, 4096, 0, 10); | ||
| 437 | |||
| 438 | /* rotary encoders */ | ||
| 439 | input_set_abs_params(input, ABS_X, 0, 0xf, 0, 1); | ||
| 440 | input_set_abs_params(input, ABS_Y, 0, 0xf, 0, 1); | ||
| 441 | input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1); | ||
| 442 | input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1); | ||
| 443 | |||
| 444 | dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 445 | if (!dev->ep4_in_urb) { | ||
| 446 | ret = -ENOMEM; | ||
| 447 | goto exit_free_idev; | ||
| 448 | } | ||
| 449 | |||
| 450 | usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev, | ||
| 451 | usb_rcvbulkpipe(usb_dev, 0x4), | ||
| 452 | dev->ep4_in_buf, EP4_BUFSIZE, | ||
| 453 | snd_usb_caiaq_ep4_reply_dispatch, dev); | ||
| 454 | |||
| 455 | snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); | ||
| 456 | |||
| 457 | break; | ||
| 329 | default: | 458 | default: |
| 330 | /* no input methods supported on this device */ | 459 | /* no input methods supported on this device */ |
| 331 | input_free_device(input); | 460 | goto exit_free_idev; |
| 332 | return 0; | ||
| 333 | } | 461 | } |
| 334 | 462 | ||
| 463 | input->open = snd_usb_caiaq_input_open; | ||
| 464 | input->close = snd_usb_caiaq_input_close; | ||
| 335 | input->keycode = dev->keycode; | 465 | input->keycode = dev->keycode; |
| 336 | input->keycodesize = sizeof(unsigned short); | 466 | input->keycodesize = sizeof(unsigned short); |
| 337 | for (i = 0; i < input->keycodemax; i++) | 467 | for (i = 0; i < input->keycodemax; i++) |
| 338 | __set_bit(dev->keycode[i], input->keybit); | 468 | __set_bit(dev->keycode[i], input->keybit); |
| 339 | 469 | ||
| 340 | ret = input_register_device(input); | 470 | ret = input_register_device(input); |
| 341 | if (ret < 0) { | 471 | if (ret < 0) |
| 342 | input_free_device(input); | 472 | goto exit_free_idev; |
| 343 | return ret; | ||
| 344 | } | ||
| 345 | 473 | ||
| 346 | dev->input_dev = input; | 474 | dev->input_dev = input; |
| 347 | return 0; | 475 | return 0; |
| 476 | |||
| 477 | exit_free_idev: | ||
| 478 | input_free_device(input); | ||
| 479 | return ret; | ||
| 348 | } | 480 | } |
| 349 | 481 | ||
| 350 | void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) | 482 | 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) | |||
| 352 | if (!dev || !dev->input_dev) | 484 | if (!dev || !dev->input_dev) |
| 353 | return; | 485 | return; |
| 354 | 486 | ||
| 487 | usb_kill_urb(dev->ep4_in_urb); | ||
| 488 | usb_free_urb(dev->ep4_in_urb); | ||
| 489 | dev->ep4_in_urb = NULL; | ||
| 490 | |||
| 355 | input_unregister_device(dev->input_dev); | 491 | input_unregister_device(dev->input_dev); |
| 356 | dev->input_dev = NULL; | 492 | dev->input_dev = NULL; |
| 357 | } | 493 | } |
