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 | } |