Commit 6207e51b authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Jaroslav Kysela

[ALSA] usb-audio: use vmalloc for the PCM buffer

USB generic driver
With the double buffering, we no longer need contiguous memory for the
PCM buffer, so we can use vmalloc() instead of the preallocation
functions, and increase the maximum size to 256 KB.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent 55851f73
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/info.h> #include <sound/info.h>
...@@ -676,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs) ...@@ -676,6 +677,42 @@ static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
} }
/* get the physical page pointer at the given offset */
static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs,
unsigned long offset)
{
void *pageptr = subs->runtime->dma_area + offset;
return vmalloc_to_page(pageptr);
}
/* allocate virtual buffer; may be called more than once */
static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size)
{
snd_pcm_runtime_t *runtime = subs->runtime;
if (runtime->dma_area) {
if (runtime->dma_bytes >= size)
return 0; /* already large enough */
vfree_nocheck(runtime->dma_area);
}
runtime->dma_area = vmalloc_nocheck(size);
if (! runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 0;
}
/* free virtual buffer; may be called more than once */
static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs)
{
snd_pcm_runtime_t *runtime = subs->runtime;
if (runtime->dma_area) {
vfree_nocheck(runtime->dma_area);
runtime->dma_area = NULL;
}
return 0;
}
/* /*
* unlink active urbs. * unlink active urbs.
*/ */
...@@ -1311,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream, ...@@ -1311,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
unsigned int channels, rate, format; unsigned int channels, rate, format;
int ret, changed; int ret, changed;
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); ret = snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -1367,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream) ...@@ -1367,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
subs->cur_rate = 0; subs->cur_rate = 0;
subs->period_bytes = 0; subs->period_bytes = 0;
release_substream_urbs(subs, 0); release_substream_urbs(subs, 0);
return snd_pcm_lib_free_pages(substream); return snd_pcm_free_vmalloc_buffer(substream);
} }
/* /*
...@@ -1406,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback = ...@@ -1406,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024), .buffer_bytes_max = (256*1024),
.period_bytes_min = 64, .period_bytes_min = 64,
.period_bytes_max = (128*1024), .period_bytes_max = (128*1024),
.periods_min = 2, .periods_min = 2,
...@@ -1418,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture = ...@@ -1418,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID), SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024), .buffer_bytes_max = (256*1024),
.period_bytes_min = 64, .period_bytes_min = 64,
.period_bytes_max = (128*1024), .period_bytes_max = (128*1024),
.periods_min = 2, .periods_min = 2,
...@@ -1810,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = { ...@@ -1810,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
.prepare = snd_usb_pcm_prepare, .prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger, .trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer, .pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
}; };
static snd_pcm_ops_t snd_usb_capture_ops = { static snd_pcm_ops_t snd_usb_capture_ops = {
...@@ -1821,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = { ...@@ -1821,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
.prepare = snd_usb_pcm_prepare, .prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger, .trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer, .pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
}; };
...@@ -2048,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat ...@@ -2048,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->ops = audio_urb_ops[stream]; subs->ops = audio_urb_ops[stream];
else else
subs->ops = audio_urb_ops_high_speed[stream]; subs->ops = audio_urb_ops_high_speed[stream];
snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_NOIO),
64 * 1024, 128 * 1024);
snd_pcm_set_ops(as->pcm, stream, snd_pcm_set_ops(as->pcm, stream,
stream == SNDRV_PCM_STREAM_PLAYBACK ? stream == SNDRV_PCM_STREAM_PLAYBACK ?
&snd_usb_playback_ops : &snd_usb_capture_ops); &snd_usb_playback_ops : &snd_usb_capture_ops);
...@@ -2097,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm) ...@@ -2097,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
snd_usb_stream_t *stream = pcm->private_data; snd_usb_stream_t *stream = pcm->private_data;
if (stream) { if (stream) {
stream->pcm = NULL; stream->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_usb_audio_stream_free(stream); snd_usb_audio_stream_free(stream);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment