diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/usb/usbaudio.c | 53 |
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 */ | ||
681 | static 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 */ | ||
689 | static 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 */ | ||
705 | static 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 | ||
1815 | static snd_pcm_ops_t snd_usb_capture_ops = { | 1854 | static 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 | } |