aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/usb/usbaudio.c53
1 files changed, 44 insertions, 9 deletions
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 13ff66b0a532..5aa5fe651a8a 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -46,6 +46,7 @@
46#include <linux/slab.h> 46#include <linux/slab.h>
47#include <linux/string.h> 47#include <linux/string.h>
48#include <linux/usb.h> 48#include <linux/usb.h>
49#include <linux/vmalloc.h>
49#include <linux/moduleparam.h> 50#include <linux/moduleparam.h>
50#include <sound/core.h> 51#include <sound/core.h>
51#include <sound/info.h> 52#include <sound/info.h>
@@ -676,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
676} 677}
677 678
678 679
680/* get the physical page pointer at the given offset */
681static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
682 unsigned long offset)
683{
684 void *pageptr = subs->runtime->dma_area + offset;
685 return vmalloc_to_page(pageptr);
686}
687
688/* allocate virtual buffer; may be called more than once */
689static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
690{
691 snd_pcm_runtime_t *runtime = subs->runtime;
692 if (runtime->dma_area) {
693 if (runtime->dma_bytes >= size)
694 return 0; /* already large enough */
695 vfree_nocheck(runtime->dma_area);
696 }
697 runtime->dma_area = vmalloc_nocheck(size);
698 if (! runtime->dma_area)
699 return -ENOMEM;
700 runtime->dma_bytes = size;
701 return 0;
702}
703
704/* free virtual buffer; may be called more than once */
705static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
706{
707 snd_pcm_runtime_t *runtime = subs->runtime;
708 if (runtime->dma_area) {
709 vfree_nocheck(runtime->dma_area);
710 runtime->dma_area = NULL;
711 }
712 return 0;
713}
714
715
679/* 716/*
680 * unlink active urbs. 717 * unlink active urbs.
681 */ 718 */
@@ -1311,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
1311 unsigned int channels, rate, format; 1348 unsigned int channels, rate, format;
1312 int ret, changed; 1349 int ret, changed;
1313 1350
1314 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); 1351 ret = snd_pcm_alloc_vmalloc_buffer(substream,
1352 params_buffer_bytes(hw_params));
1315 if (ret < 0) 1353 if (ret < 0)
1316 return ret; 1354 return ret;
1317 1355
@@ -1367,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
1367 subs->cur_rate = 0; 1405 subs->cur_rate = 0;
1368 subs->period_bytes = 0; 1406 subs->period_bytes = 0;
1369 release_substream_urbs(subs, 0); 1407 release_substream_urbs(subs, 0);
1370 return snd_pcm_lib_free_pages(substream); 1408 return snd_pcm_free_vmalloc_buffer(substream);
1371} 1409}
1372 1410
1373/* 1411/*
@@ -1406,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
1406 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 1444 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1407 SNDRV_PCM_INFO_BLOCK_TRANSFER | 1445 SNDRV_PCM_INFO_BLOCK_TRANSFER |
1408 SNDRV_PCM_INFO_MMAP_VALID), 1446 SNDRV_PCM_INFO_MMAP_VALID),
1409 .buffer_bytes_max = (128*1024), 1447 .buffer_bytes_max = (256*1024),
1410 .period_bytes_min = 64, 1448 .period_bytes_min = 64,
1411 .period_bytes_max = (128*1024), 1449 .period_bytes_max = (128*1024),
1412 .periods_min = 2, 1450 .periods_min = 2,
@@ -1418,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
1418 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 1456 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
1419 SNDRV_PCM_INFO_BLOCK_TRANSFER | 1457 SNDRV_PCM_INFO_BLOCK_TRANSFER |
1420 SNDRV_PCM_INFO_MMAP_VALID), 1458 SNDRV_PCM_INFO_MMAP_VALID),
1421 .buffer_bytes_max = (128*1024), 1459 .buffer_bytes_max = (256*1024),
1422 .period_bytes_min = 64, 1460 .period_bytes_min = 64,
1423 .period_bytes_max = (128*1024), 1461 .period_bytes_max = (128*1024),
1424 .periods_min = 2, 1462 .periods_min = 2,
@@ -1810,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
1810 .prepare = snd_usb_pcm_prepare, 1848 .prepare = snd_usb_pcm_prepare,
1811 .trigger = snd_usb_pcm_trigger, 1849 .trigger = snd_usb_pcm_trigger,
1812 .pointer = snd_usb_pcm_pointer, 1850 .pointer = snd_usb_pcm_pointer,
1851 .page = snd_pcm_get_vmalloc_page,
1813}; 1852};
1814 1853
1815static snd_pcm_ops_t snd_usb_capture_ops = { 1854static snd_pcm_ops_t snd_usb_capture_ops = {
@@ -1821,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
1821 .prepare = snd_usb_pcm_prepare, 1860 .prepare = snd_usb_pcm_prepare,
1822 .trigger = snd_usb_pcm_trigger, 1861 .trigger = snd_usb_pcm_trigger,
1823 .pointer = snd_usb_pcm_pointer, 1862 .pointer = snd_usb_pcm_pointer,
1863 .page = snd_pcm_get_vmalloc_page,
1824}; 1864};
1825 1865
1826 1866
@@ -2048,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
2048 subs->ops = audio_urb_ops[stream]; 2088 subs->ops = audio_urb_ops[stream];
2049 else 2089 else
2050 subs->ops = audio_urb_ops_high_speed[stream]; 2090 subs->ops = audio_urb_ops_high_speed[stream];
2051 snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
2052 SNDRV_DMA_TYPE_CONTINUOUS,
2053 snd_dma_continuous_data(GFP_NOIO),
2054 64 * 1024, 128 * 1024);
2055 snd_pcm_set_ops(as->pcm, stream, 2091 snd_pcm_set_ops(as->pcm, stream,
2056 stream == SNDRV_PCM_STREAM_PLAYBACK ? 2092 stream == SNDRV_PCM_STREAM_PLAYBACK ?
2057 &snd_usb_playback_ops : &snd_usb_capture_ops); 2093 &snd_usb_playback_ops : &snd_usb_capture_ops);
@@ -2097,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
2097 snd_usb_stream_t *stream = pcm->private_data; 2133 snd_usb_stream_t *stream = pcm->private_data;
2098 if (stream) { 2134 if (stream) {
2099 stream->pcm = NULL; 2135 stream->pcm = NULL;
2100 snd_pcm_lib_preallocate_free_for_all(pcm);
2101 snd_usb_audio_stream_free(stream); 2136 snd_usb_audio_stream_free(stream);
2102 } 2137 }
2103} 2138}