Skip to content

Commit

Permalink
[ALSA] usb-audio: use vmalloc for the PCM buffer
Browse files Browse the repository at this point in the history
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: Clemens Ladisch <clemens@ladisch.de>
  • Loading branch information
Clemens Ladisch authored and Jaroslav Kysela committed Aug 30, 2005
1 parent 55851f7 commit 6207e51
Showing 1 changed file with 44 additions and 9 deletions.
53 changes: 44 additions & 9 deletions sound/usb/usbaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
#include <sound/info.h>
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -1311,7 +1348,8 @@ static int snd_usb_hw_params(snd_pcm_substream_t *substream,
unsigned int channels, rate, format;
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)
return ret;

Expand Down Expand Up @@ -1367,7 +1405,7 @@ static int snd_usb_hw_free(snd_pcm_substream_t *substream)
subs->cur_rate = 0;
subs->period_bytes = 0;
release_substream_urbs(subs, 0);
return snd_pcm_lib_free_pages(substream);
return snd_pcm_free_vmalloc_buffer(substream);
}

/*
Expand Down Expand Up @@ -1406,7 +1444,7 @@ static snd_pcm_hardware_t snd_usb_playback =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024),
.buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
Expand All @@ -1418,7 +1456,7 @@ static snd_pcm_hardware_t snd_usb_capture =
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.buffer_bytes_max = (128*1024),
.buffer_bytes_max = (256*1024),
.period_bytes_min = 64,
.period_bytes_max = (128*1024),
.periods_min = 2,
Expand Down Expand Up @@ -1810,6 +1848,7 @@ static snd_pcm_ops_t snd_usb_playback_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
};

static snd_pcm_ops_t snd_usb_capture_ops = {
Expand All @@ -1821,6 +1860,7 @@ static snd_pcm_ops_t snd_usb_capture_ops = {
.prepare = snd_usb_pcm_prepare,
.trigger = snd_usb_pcm_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_get_vmalloc_page,
};


Expand Down Expand Up @@ -2048,10 +2088,6 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
subs->ops = audio_urb_ops[stream];
else
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,
stream == SNDRV_PCM_STREAM_PLAYBACK ?
&snd_usb_playback_ops : &snd_usb_capture_ops);
Expand Down Expand Up @@ -2097,7 +2133,6 @@ static void snd_usb_audio_pcm_free(snd_pcm_t *pcm)
snd_usb_stream_t *stream = pcm->private_data;
if (stream) {
stream->pcm = NULL;
snd_pcm_lib_preallocate_free_for_all(pcm);
snd_usb_audio_stream_free(stream);
}
}
Expand Down

0 comments on commit 6207e51

Please sign in to comment.